Monday, June 20, 2016

Google map api v3 with Ionic framework

My web was using Ionic framwork 1.x. After I read some threads and examples on the web, initiate the google map as following is the only way I can make the map show up.

index.html
<script src="http://maps.googleapis.com/maps/api/js?key=yourAPIkey&libraries=places" async defer></script>              

view html:
 <ion-header-bar class="bar bar-header bar-positive" ng-init="initMap()"></ion-header-bar>

<ion-content>          
       <div id="map" data-tap-disabled="true"></div>          
</ion-content>

javascript:
$scope.initMap = function() {
        $scope.directionsService = new google.maps.DirectionsService;
        $scope.directionsDisplay = new google.maps.DirectionsRenderer({
            suppressMarkers:true,
            preserveViewport: true
            //polylineOptions: { strokeColor: "red" }
        });
        var mylocation = new google.maps.LatLng('41.72', '-71.93');
        var grayStyles = [
            {   featureType: "all",
                elementType: "labels.text",
                stylers: [
                  { gamma: 0.01 }
                ]
            },
        ];
        var mapOptions = {
            center: mylocation,
            zoom: 11,
            styles: grayStyles,
            mapTypeId: google.maps.MapTypeId.ROADMAP
        };
        var map = new google.maps.Map(document.getElementById("map"),
            mapOptions);      
        $scope.directionsDisplay.setMap(map);  
        var trafficLayer = new google.maps.TrafficLayer();
        trafficLayer.setMap(map);

        marker = new google.maps.Marker({
            position: mylocation ,
            icon: "http://maps.google.com/mapfiles/kml/pal3/icon48.png",
            map: map
        });
        marker.infowindow = new google.maps.InfoWindow({                  
            content: 'My xxx Inc.'
        });              
        google.maps.event.addListener(marker, 'click', (function(marker) {
            return function() {                          
                    marker.infowindow.open(map, marker);
            }
        })(marker));  
     
        $scope.map = map;            
             
    };

Android Webview call Angular controller function.

Since the web is written with AngularJS 1.x, things are working with $scope that it does not look alike simple javascript; anyway, here is how I call a function declared in a controller successfully through Webview.

Android webview:
myWebView.loadUrl("javascript:drvAppDevicePosition('" + mLat + "','" + mLng + "');");


Javascript:
window.drvAppDevicePosition = function(a, b) {      
        $scope.$apply(function() {          
                console.log("Lat:"+a+"; Lng:"+b);
        });      
    };



Android - Capture Signature

Recently, I implemented an App ran on Android for capture signature.
There are some examples on the web that I can taken for reference.
I also wanna share mine here if someone is also looking for this.


public class CaptureSignature extends Activity {
    LinearLayout mContent;
    SignatureView mSignature;
    Button mClear, mGetSign, mCancel;
    public static String tempDir;
    public String current = null;
    private Bitmap mBitmap;
    View mView;
    File mypath;

    @Override    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.signature);
        getWindow().setLayout(ViewGroup.LayoutParams.MATCH_PARENT, 
ViewGroup.LayoutParams.MATCH_PARENT);

        tempDir = Environment.getExternalStoragePublicDirectory( 
Environment.DIRECTORY_DOWNLOADS) 
+ "/" + getResources().getString(R.string.external_dir) + "/";

        ContextWrapper cw = new ContextWrapper(getApplicationContext());
        File directory = cw.getDir(getResources().getString(R.string.external_dir), 
Context.MODE_PRIVATE);

        prepareDirectory();
        current = "mySignaturre.png";

        mypath= new File(tempDir,current);

        mContent = (LinearLayout) findViewById(R.id.linearLayout);
        mSignature = new SignatureView(this, null);

        mSignature.setBackgroundColor(Color.WHITE);

        mContent.addView(mSignature);
        mClear = (Button)findViewById(R.id.clear);
        mGetSign = (Button)findViewById(R.id.getsign);
        mGetSign.setEnabled(false);
        mCancel = (Button)findViewById(R.id.cancel);
        mView = mContent;


        mClear.setOnClickListener(new OnClickListener()
        {
            public void onClick(View v)
            {
                mSignature.clear();
                mGetSign.setEnabled(false);
            }
        });

        mGetSign.setOnClickListener(new OnClickListener()
        {
            public void onClick(View v)
            {        
                boolean error = captureSignature();
                if(!error){
                    mView.setDrawingCacheEnabled(true);
                    mSignature.save(mView);
                    finish();
                }
            }
        });

        mCancel.setOnClickListener(new OnClickListener()
        {
            public void onClick(View v)
            {
            finish();
            }
        });

    }

    @Override    protected void onDestroy() {
        super.onDestroy();
    }

    private boolean captureSignature() {
        boolean error = false;
        String errorMessage = "";
        if(error){
        }
        return error;
    }

    private String getTodaysDate() {
        final Calendar c = Calendar.getInstance();
        int todaysDate =     (c.get(Calendar.YEAR) * 10000) +
                ((c.get(Calendar.MONTH) + 1) * 100) +
                (c.get(Calendar.DAY_OF_MONTH));
        return(String.valueOf(todaysDate));
    }

    private String getCurrentTime() {
        final Calendar c = Calendar.getInstance();
        int currentTime =     (c.get(Calendar.HOUR_OF_DAY) * 10000) +
                (c.get(Calendar.MINUTE) * 100) +
                (c.get(Calendar.SECOND));
        return(String.valueOf(currentTime));
    }

    private boolean prepareDirectory()
    {
        try {
            if (makedirs())
            {
                return true;
            } else {
                return false;
            }
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    private boolean makedirs()
    {
        File tempdir = new File(tempDir);
        if (!tempdir.exists())
            tempdir.mkdirs();

        return true;
    }

    public class SignatureView extends View
    {
        private static final float STROKE_WIDTH = 18f;
        private static final float HALF_STROKE_WIDTH = STROKE_WIDTH / 2;
        private Paint paint = new Paint();
        private Path path = new Path();

        private float lastTouchX;
        private float lastTouchY;
        private final RectF dirtyRect = new RectF();

        public SignatureView(Context context, AttributeSet attrs)
        {
            super(context, attrs);
            paint.setAntiAlias(true);
            paint.setColor(Color.BLACK);
            paint.setStyle(Paint.Style.STROKE);
            paint.setStrokeJoin(Paint.Join.ROUND);
            paint.setStrokeWidth(STROKE_WIDTH);
        }

        public void save(View v)
        {
            if(mBitmap == null)
            {
                mBitmap =  Bitmap.createBitmap (mContent.getWidth(), mContent.getHeight(), 
Bitmap.Config.RGB_565);
            }
            Canvas canvas = new Canvas(mBitmap);

            try            {
                //Remove the old Signature if exists.                
                boolean deleted = mypath.delete();
                FileOutputStream mFileOutStream = new FileOutputStream(mypath);

                v.draw(canvas);
                mBitmap.compress(Bitmap.CompressFormat.PNG, 90, mFileOutStream);
                mFileOutStream.flush();
                mFileOutStream.close();
                String url = Images.Media.insertImage(getContentResolver(), mBitmap, "title", 
null);

            }
            catch(Exception e)
            {
                Log.v("log_tag", e.toString());
            }
        }

        public void clear()
        {
            path.reset();
            invalidate();
        }

        @Override        protected void onDraw(Canvas canvas)
        {
            canvas.drawPath(path, paint);
        }

        @Override        public boolean onTouchEvent(MotionEvent event)
        {
            float eventX = event.getX();
            float eventY = event.getY();
            mGetSign.setEnabled(true);

            switch (event.getAction())
            {
                case MotionEvent.ACTION_DOWN:
                    path.moveTo(eventX, eventY);
                    lastTouchX = eventX;
                    lastTouchY = eventY;
                    return true;

                case MotionEvent.ACTION_MOVE:

                case MotionEvent.ACTION_UP:

                    resetDirtyRect(eventX, eventY);
                    int historySize = event.getHistorySize();
                    for (int i = 0; i < historySize; i++)
                    {
                        float historicalX = event.getHistoricalX(i);
                        float historicalY = event.getHistoricalY(i);
                        expandDirtyRect(historicalX, historicalY);
                        path.lineTo(historicalX, historicalY);
                    }
                    path.lineTo(eventX, eventY);
                    break;

                default:
                    debug("Ignored touch event: " + event.toString());
                    return false;
            }

            invalidate((int) (dirtyRect.left - HALF_STROKE_WIDTH),
                    (int) (dirtyRect.top - HALF_STROKE_WIDTH),
                    (int) (dirtyRect.right + HALF_STROKE_WIDTH),
                    (int) (dirtyRect.bottom + HALF_STROKE_WIDTH));

            lastTouchX = eventX;
            lastTouchY = eventY;

            return true;
        }

        private void debug(String string){
        }

        private void expandDirtyRect(float historicalX, float historicalY)
        {
            if (historicalX < dirtyRect.left)
            {
                dirtyRect.left = historicalX;
            }
            else if (historicalX > dirtyRect.right)
            {
                dirtyRect.right = historicalX;
            }

            if (historicalY < dirtyRect.top)
            {
                dirtyRect.top = historicalY;
            }
            else if (historicalY > dirtyRect.bottom)
            {
                dirtyRect.bottom = historicalY;
            }
        }

        private void resetDirtyRect(float eventX, float eventY)
        {
            dirtyRect.left = Math.min(lastTouchX, eventX);
            dirtyRect.right = Math.max(lastTouchX, eventX);
            dirtyRect.top = Math.min(lastTouchY, eventY);
            dirtyRect.bottom = Math.max(lastTouchY, eventY);
        }
    }

}





AndroidMainfest.xml:

<activity android:name=".CaptureSignature" android:label="Signature Confirmation"  
  android:screenOrientation="landscape"   
 android:theme="@android:style/Theme.Dialog" />


signature.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    
android:orientation="vertical" android:layout_width="match_parent"   
 android:layout_height="fill_parent">
    <LinearLayout android:layout_height="wrap_content"        
android:id="@+id/linearLayout2" android:layout_width="match_parent">
        <Button android:layout_height="50dp" android:layout_weight=".30"            
android:text="Cancel" android:layout_width="0dp" android:id="@+id/cancel" />
        <Button android:layout_height="50dp" android:layout_weight=".35"            
android:text="Clear" android:layout_width="0dp" android:id="@+id/clear" />
        <Button android:layout_height="50dp" android:layout_weight=".35"            
android:text="Confirm" android:layout_width="0dp" android:id="@+id/getsign" />
    </LinearLayout>
    <TableLayout android:layout_height="wrap_content"        
android:id="@+id/tableLayout1" android:layout_width="match_parent">
        <TableRow android:id="@+id/tableRow3" 
android:layout_width="wrap_content"            android:layout_height="wrap_content">
        </TableRow>
    </TableLayout>
    <LinearLayout android:layout_height="match_parent"        
android:orientation="vertical"        android:id="@+id/linearLayout" 
android:layout_width="match_parent" />
</LinearLayout>