Tuesday, 28 February 2017

Android Google Maps with Current Location Demo Part 2

In this article i'll continue google maps into your android application and adding current location using Google Api Client with Location listener using Fuse Api.

Here i'll be handling Android runtime permission to enable Fine location permission for Fetching current location of users running 6.0 or above.

Location dialog will also be available to prompt user to enable location services so that fuse api can fetch the user's current location.

1. Add latest google play services dependency to your module gradle for eg :

dependencies {
  compile fileTree(dir: 'libs', include: ['*.jar'])
  compile 'com.android.support:appcompat-v7:25.0.0' 
  compile 'com.google.android.gms:play-services:10.2.0'
}


2. Add Api keys and google play services version to the manifest file.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="kamal.com.androidv2mapsdemo">

 <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">        <activity android:name=".MapsActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <!--Defining Map Configs here. Including Google play services version and Map Key-->
        <meta-data
            android:name="com.google.android.gms.version"
            android:value="@integer/google_play_services_version" />
        <meta-data
            android:name="com.google.android.geo.API_KEY"
            android:value="Your Api key" />
    </application>

</manifest>

3. Add a container to add map on runtime in Xml layout.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/activity_maps"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <!-- The map fragments will go here -->
    <RelativeLayout
        android:id="@+id/map_container"
        android:layout_width="match_parent"
        android:layout_height="match_parent"></RelativeLayout>

</RelativeLayout>

4. MapsActivity to inflate map.
 import android.app.Dialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentSender;
import android.content.pm.PackageManager;
import android.location.Location;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.ActivityCompat;
import android.support.v4.app.FragmentManager;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.widget.Toast;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GoogleApiAvailability;
import com.google.android.gms.common.GooglePlayServicesUtil;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.PendingResult;
import com.google.android.gms.common.api.ResultCallbacks;
import com.google.android.gms.common.api.Status;
import com.google.android.gms.location.LocationListener;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationServices;
import com.google.android.gms.location.LocationSettingsRequest;
import com.google.android.gms.location.LocationSettingsResult;
import com.google.android.gms.location.LocationSettingsStates;
import com.google.android.gms.location.LocationSettingsStatusCodes;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.OnMapReadyCallback;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.BitmapDescriptorFactory;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.MarkerOptions;


public class MapsActivity extends AppCompatActivity implements
        OnMapReadyCallback , GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, LocationListener {

    private GoogleMap googleMap;
    private SupportMapFragment fragment;
    private GoogleApiClient mGoogleApiClient;

    /**
     * The desired interval for location updates. Inexact. Updates may be more or less frequent.
     */
    public static final long UPDATE_INTERVAL_IN_MILLISECONDS = 10000;
    /**
     * The fastest rate for active location updates. Exact. Updates will never be more frequent
     * than this value.
     */
    public static final long FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS =
            UPDATE_INTERVAL_IN_MILLISECONDS / 2;
    /**
     * Stores parameters for requests to the FusedLocationProviderApi.
     */
    protected LocationRequest mLocationRequest;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_maps);
        setupDynamicMapFragment();
        if(checkGooglePlayServicesAvailable())
        initializeMap();
    }

    private void setupDynamicMapFragment() {
        FragmentManager fm = this.getSupportFragmentManager();
        fragment = (SupportMapFragment) fm.findFragmentById(R.id.map_container);
        if (fragment == null) {
            fragment = SupportMapFragment.newInstance();
            fm.beginTransaction().replace(R.id.map_container, fragment).commit();
        }
    }


    /**
     * function to load map. If map is not created it will create it for you
     */
    private void initializeMap() {
        if (googleMap == null) {
            fragment.getMapAsync(this);
        }
    }


    @Override
    public void onMapReady(GoogleMap googleMap) {
        this.googleMap=googleMap;
        if (googleMap != null) {
            googleMap.getUiSettings().setMapToolbarEnabled(false);
            if (Build.VERSION.SDK_INT < 23) {
                googleMap.setMyLocationEnabled(true);
                buildGoogleApiClient();
            }else{
                checkFineLocationPermission();
            }
        }
    }


    protected synchronized void buildGoogleApiClient() {
        Toast.makeText(this,"buildGoogleApiClient", Toast.LENGTH_SHORT).show();
        mGoogleApiClient = new GoogleApiClient.Builder(this)
                .addConnectionCallbacks(this)
                .addOnConnectionFailedListener(this)
                .addApi(LocationServices.API)
                .build();
        mGoogleApiClient.connect();
    }

    /**
     * Check whether Google Play Services are available.
     *
     * If not, then display dialog allowing user to update Google Play Services
     *
     * @return true if available, or false if not
     */
    private boolean checkGooglePlayServicesAvailable( )
    {
        GoogleApiAvailability googleAPI = GoogleApiAvailability.getInstance();
        final int status = googleAPI.isGooglePlayServicesAvailable(this);
        if (status == ConnectionResult.SUCCESS)
        {
            return true;
        }
        Log.e("", "Google Play Services not available: " + GooglePlayServicesUtil.getErrorString(status));

        if (googleAPI.isUserResolvableError(status))
        {
            final Dialog errorDialog = GooglePlayServicesUtil.getErrorDialog(status, this, 1);
            if (errorDialog != null)
            {
                errorDialog.show();
            }
        }
        return false;
    }


    @Override
    public void onConnected(@Nullable Bundle bundle) {
        Toast.makeText(this,"onConnected",Toast.LENGTH_SHORT).show();
        //mLocationRequest.setSmallestDisplacement(0.1F); //1/10 meter
        mLocationRequest = new LocationRequest();
        mLocationRequest.setInterval(5000); //5 seconds
        mLocationRequest.setFastestInterval(3000); //3 seconds
        mLocationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
        LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder()
                .addLocationRequest(mLocationRequest);
        PendingResult<LocationSettingsResult> result =
                LocationServices.SettingsApi.checkLocationSettings(mGoogleApiClient,
                        builder.build());
        result.setResultCallback(new ResultCallbacks<LocationSettingsResult>() {
            @Override
            public void onSuccess(@NonNull LocationSettingsResult result) {
                final Status status = result.getStatus();
                final LocationSettingsStates s= result.getLocationSettingsStates();
                switch (status.getStatusCode()) {
                    case LocationSettingsStatusCodes.SUCCESS:
                        // All location settings are satisfied. The client can
                        // initialize location requests here.
                        LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, MapsActivity.this);
                        break;
                    case LocationSettingsStatusCodes.RESOLUTION_REQUIRED:
                        // Location settings are not satisfied, but this can be fixed
                        // by showing the user a dialog.
                        try {
                            // Show the dialog by calling startResolutionForResult(),
                            // and check the result in onActivityResult().
                            status.startResolutionForResult(
                                    MapsActivity.this,
                                    100);
                        } catch (IntentSender.SendIntentException e) {
                            // Ignore the error.
                        }
                        break;
                    case LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE:
                        // Location settings are not satisfied. However, we have no way
                        // to fix the settings so we won't show the dialog.
                        break;
                }
            }


            @Override
            public void onFailure(@NonNull Status status) {
                Log.e("","");
                try {
                    status.startResolutionForResult(MapsActivity.this, 100);
                } catch (IntentSender.SendIntentException e) {
                    e.printStackTrace();
                }
            }
        }) ;
    }



    @Override
    public void onConnectionSuspended(int i) {
    }

    @Override
    public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {

    }


    @Override
    public void onLocationChanged(Location location) {
        //Place current location marker
        LatLng latLng = new LatLng(location.getLatitude(), location.getLongitude());
        MarkerOptions markerOptions = new MarkerOptions();
        markerOptions.position(latLng);
        markerOptions.title("Current Position");
        markerOptions.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_MAGENTA));
        googleMap.addMarker(markerOptions);

        //move map camera
        googleMap.moveCamera(CameraUpdateFactory.newLatLng(latLng));
        googleMap.animateCamera(CameraUpdateFactory.zoomTo(5));


        //stop location updates
        if (mGoogleApiClient != null) {
            LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);
        }

    }


    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if(requestCode==100 ){
            LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);
        }
    }


    /**
     *   Write external Permission check
     */
    private void checkFineLocationPermission(){
        if ((ContextCompat.checkSelfPermission(this,  android.Manifest.permission.ACCESS_FINE_LOCATION))
                != PackageManager.PERMISSION_GRANTED) {
            // This condition checks whether user has earlier denied the permission or not just by clicking on deny in the permission dialog.
            //Remember not on the never ask check box then deny in the permission dialog
            if (ActivityCompat.shouldShowRequestPermissionRationale(this,
                    android.Manifest.permission.ACCESS_FINE_LOCATION)) {
                /**
                 * Show an explanation to user why this permission in needed by us. Here using alert dialog to show the permission use.
                 */
                new AlertDialog.Builder(this)
                        .setTitle("Permission Required")
                        .setMessage("This permission was denied earlier by you. This permission is required to use card.")
                        .setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
                            public void onClick(DialogInterface dialog, int which) {
                                dialog.dismiss();
                                ActivityCompat.requestPermissions(MapsActivity.this,
                                        new String[]{android.Manifest.permission.ACCESS_FINE_LOCATION},
                                        4);
                            }
                        })
                        .setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() {
                            public void onClick(DialogInterface dialog, int which) {
                                dialog.dismiss();
                            }
                        })
                        .setIcon(android.R.drawable.ic_dialog_alert)
                        .show();
            } else {
                //Just ask for the permission for first time. This block will come into play when user is trying to use feature which requires permission grant.
                //So for the first time user will be into this else block. So just ask for the permission you need by showing default permission dialog
                ActivityCompat.requestPermissions(MapsActivity.this,
                        new String[]{android.Manifest.permission.ACCESS_FINE_LOCATION}, 4);
            }
        }else {
            // If permission is already granted by user then we will be into this else block. So do whatever is required here
            //            Toast.makeText(this,"Permission Already granted",Toast.LENGTH_LONG).show();
            googleMap.setMyLocationEnabled(true);
            buildGoogleApiClient();
        }
    }



    /**
     *  This method will be invoked when user allows or deny's a permission from the permission dialog so take actions accordingly.
     * @param requestCode : returns requestCode
     * @param permissions : returns permissions
     * @param grantResults : returns grantResults
     */
    @Override
    public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        switch (requestCode) {
            case 4:
                if (grantResults.length > 0
                        && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    googleMap.setMyLocationEnabled(true);
                    buildGoogleApiClient();
                } else {
                    String permission = permissions[0];
                    boolean showRationale = ActivityCompat.shouldShowRequestPermissionRationale(this, permission);
                    if (!showRationale) {
                        //We will be in this block when User has ticked the never show dialog and denied the permission from the permission dialog
                        //Here we can not request the permission again if user has denied the permission with never ask option enabled.
                        //Only way is to show a imfo dialog and ask user to grant the permission from settings.
                        Toast.makeText(this, "Write Storage Permission Denied with never show options." +
                                        "Please manually enable the permission and re-start the app to use this feature.",
                                Toast.LENGTH_LONG).show();
                    } else {
                        Toast.makeText(this, "Write Storage Permission Denied", Toast.LENGTH_LONG).show();
                    }
                }
                break;
            default:
        }
    }

}
Now you can see users current location on google maps.


Download the full source code from : Android Google Maps Demo Link

Cheers!!

Monday, 27 February 2017

Android Google Map Demo part 1

In this article i'll be discussing how to easily integrate maps into your android application. So to start firstly you would need to setup your android app as normally we do. Before starting please create your project on Google web console and obtain required Api keys for Google Maps using SHA1 fingerprint of you System,

1. Add latest Google Play Services Dependency to your module gradle for eg :

dependencies {
  compile fileTree(dir: 'libs', include: ['*.jar'])
  compile 'com.android.support:appcompat-v7:25.0.0' 
  compile 'com.google.android.gms:play-services:10.2.0'
}


2. Add Api Keys and Google Play Services Version to the manifest file.


<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="kamal.com.androidv2mapsdemo">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MapsActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <!--Defining Map Configs here. Including Google play services version and Map Key-->
        <meta-data
            android:name="com.google.android.gms.version"
            android:value="@integer/google_play_services_version" />
        <meta-data
            android:name="com.google.android.geo.API_KEY"
            android:value="Your Api key" />
    </application>

</manifest>


3. Add a container to add map on runtime in Xml layout.


<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/activity_maps"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <!-- The map fragments will go here -->
    <RelativeLayout
        android:id="@+id/map_container"
        android:layout_width="match_parent"
        android:layout_height="match_parent"></RelativeLayout>

</RelativeLayout>


4. MapsActivity to inflate map.

package kamal.com.androidv2mapsdemo;

import android.app.Dialog;
import android.os.Bundle;
import android.support.v4.app.FragmentManager;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GoogleApiAvailability;
import com.google.android.gms.common.GooglePlayServicesUtil;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.OnMapReadyCallback;
import com.google.android.gms.maps.SupportMapFragment;

public class MapsActivity extends AppCompatActivity implements
        OnMapReadyCallback {
    private GoogleMap googleMap;
    private SupportMapFragment fragment;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_maps);
        setupDynamicMapFragment();
        if(checkGooglePlayServicesAvailable())
        initializeMap();
    }


    private void setupDynamicMapFragment() {
        FragmentManager fm = this.getSupportFragmentManager();
        fragment = (SupportMapFragment) fm.findFragmentById(R.id.map_container);
        if (fragment == null) {
            fragment = SupportMapFragment.newInstance();
            fm.beginTransaction().replace(R.id.map_container, fragment).commit();
        }
    }


    /**
     * function to load map. If map is not created it will create it for you
     */
    private void initializeMap() {
        if (googleMap == null) {
            fragment.getMapAsync(this);
        }
    }


    @Override
    public void onMapReady(GoogleMap googleMap) {
        this.googleMap=googleMap;
        if (googleMap != null) {
            googleMap.getUiSettings().setMapToolbarEnabled(false);
        }
    }


    /**
     * Check whether Google Play Services are available.
     *
     * If not, then display dialog allowing user to update Google Play Services
     *
     * @return true if available, or false if not
     */
    private boolean checkGooglePlayServicesAvailable( )
    {
        GoogleApiAvailability googleAPI = GoogleApiAvailability.getInstance();
        final int status = googleAPI.isGooglePlayServicesAvailable(this);
        if (status == ConnectionResult.SUCCESS)
        {
            return true;
        }

        Log.e("", "Google Play Services not available: " + GooglePlayServicesUtil.getErrorString(status));

        if (googleAPI.isUserResolvableError(status))
        {
            final Dialog errorDialog = GooglePlayServicesUtil.getErrorDialog(status, this, 1);
            if (errorDialog != null)
            {
                errorDialog.show();
            }
        }

        return false;
    }

}


That's it, We are done with Google maps for this article. You can see your google maps now.



Cheers!!

Tuesday, 12 July 2016

Opening Android App When Particular link/Host with Scheme is opened in Browser.

Opening Android Application when particular "Host" is opened in Android mobile browser or particular Link is opened Also named as Mobile DeepLinking.

We need to define host & scheme in the intent filters of the activity, which we need to open when link or host is opened.


Below is the code for opening app when particular Host is opened.

 <activity


            android:name=".ActivityName">
<intent-filter>

                <action android:name="android.intent.action.GALLERY" />
                <category android:name="android.intent.category.BROWSABLE" />
                <category android:name="android.intent.category.DEFAULT" />
<data
                    android:host="http"
                    android:scheme="abc.com" /> 
</intent-filter>

</activity>

Below is the code for opening app when we are trying particular Link  in browser.


 <activity

        android:name=".ActivityName">
        <intent-filter>
            <action android:name="android.intent.action.VIEW" />
            <category android:name="android.intent.category.DEFAULT" />
            <category android:name="android.intent.category.BROWSABLE" />
            <data android:scheme="http"
                  android:host="abc.com"
                  android:pathPrefix="/images/" />
            <data android:scheme="https"
                  android:host="abc.com"
                  android:pathPrefix="/images/" />
        </intent-filter>
   </activity>
 
   
Cheers!!   

Thursday, 7 July 2016

Firebase (via Assistant) Crash Reporting In Android Studio 2.2 Preview

Hi Guys, Today i'll be discussing how to use Firebase which is present as a Assistant in Android Studio 2.2.1 Preview.

As we know Firebase is a Cloud Services Provider which was acquired by Google back in 2014 in order to help developer build better real-time apps.

Now Firebase will be available as Assistant in Android Studio upcoming version which will help us easliy integrate following :

1. Analytics
2. Cloud Messaging
3. Authenication
4. Real time Database
5. Storage
6. Crash Reporting etc..

Now using Assistant present in Android Studio to use/integrate one the above services is quite easy and fast.

Here i'll be going through the steps to integrate Crash Reporting via Firebase in one of my demo app.

By Crash Reporting you can track all the crashes that occurs in your app and rectify once to get the report via Firebase.

So here are the steps :

1. Go to Tools and select Firebase.





2. You will see the Assistant opened in the right side in a tab named Assistant.

3. Now Scroll down and click on Crash Reporting






4. Click on Setup Firebase Crash reporting







5. Now  This will ask to to connect to Firebase.

6. Once you click on Connect it will take you to Browser and ask you to login via Google Account and will ask for permission.





7. After that Successful login you will be re-directed to Firebase Console and you can come back to Android Studio where it shows connected.





Note : This will automatically create your project inside google web console. Where make sure your Firebase Api is Enable for the project in case if you face
crash reporting problems.

8. Now you need to create a new Firebase project or select the existing Firebase Google project in which we wish to integrate Firebase.






Here you can create a new Firebase project.

After you select/create Firebase project and connect then it shows progress in Assistant like this :





Now once you are connected Assistance show you as connected as well.




After this we are all done setting up Firebase project and connection. Now Lets come to Coding part which is also a small part to do.

9. Now you need to add following Classpath into your buildscript dependencies

buildscript {
    // ...
    dependencies {
        // ...
        classpath 'com.google.gms:google-services:3.0.0'
    }
}

10. After that you need to add following dependencies in your app level build.gradle

android {

    // ...

}

dependencies {

    // ..

    compile 'com.google.firebase:firebase-ads:9.2.0'

}

// ADD THIS AT THE BOTTOM

apply plugin: 'com.google.gms.google-services'

Note : Make sure you are using the latest version of Firebase and Google play services here 11. Add following dependencies to app level build.gradle as well
    compile 'com.google.android.gms:play-services:9.2.0'
12. Now all is done. You can following code lines to track crashes
FirebaseCrash.logcat(Log.ERROR, TAG, "NPE caught");
FirebaseCrash.report(ex);
This Lines will send crash reports to cloud. And you can login to console and check the crash reports easliy there.

Note : Every crash is visible on console only after 20-25 minutes after it is reported.


In one of my demos i've created arithmetic exception to check the Firebase something like this :


try { int i = 10 / 0; }catch (Exception e){ FirebaseCrash.logcat(Log.ERROR, "Crash", "NPE caught"); FirebaseCrash.report(e); }


Which reported the Crash to console which was available to check after 20-25 minutes.
Once Crash occurs Firebase service starts and sends the crash details up to cloud.

You can find the below log in you logcat when Firebase service runs successfully.


Logcat Details which ensures Firebase Sent the Report successfully :

D/FirebaseCrashApiImpl: throwable java.lang.ArithmeticException: divide by zero
I/FirebaseCrashReceiverServiceImpl: FirebaseCrashReceiverServiceImpl created by
ClassLoader com.google.android.chimera.container.internal.DelegateLastPathClassLoader
[DexPathList[[zip file "/data/user/0/com.google.android.gms/app_chimera/m/00000005/
DynamiteModulesC_GmsCore_prodmnc_xxhdpi_release.apk"],nativeLibraryDirectories=
[/data/user/0/com.google.android.gms/app_chimera/m/00000005/n/armeabi-v7a,
/data/user/0/com.google.android.gms/app_chimera/m/00000005/n/armeabi,
/vendor/lib, /system/lib]]]  com.youpackage:background_crash D/FirebaseCrashReceiverServiceImpl: onCreate
com.youpackage:background_crash I/DynamiteModule: Considering local module com.google.android.gms.flags:0 and remote module com.google.android.gms.flags:1
com.youpackage:background_crash I/DynamiteModule: Selected remote version of com.google.android.gms.flags, version >= 1
com.youpackage:background_crash D/FirebaseCrashReceiverServiceImpl: Saving crash
com.youpackage:background_crash I/FirebaseCrashSenderServiceImpl: FirebaseCrashSenderServiceImpl created by ClassLoader com.google.android.chimera.container.internal.DelegateLastPathClassLoader[DexPathList[[zip file "/data/user/0/com.google.android.gms/app_chimera/m/00000005/DynamiteModulesC_GmsCore_prodmnc_xxhdpi_release.apk"],nativeLibraryDirectories=[/data/user/0/com.google.android.gms/app_chimera/m/00000005/n/armeabi-v7a, /data/user/0/com.google.android.gms/app_chimera/m/00000005/n/armeabi, /vendor/lib, /system/lib]]]


D/FirebaseCrashSenderServiceImpl: Response code: 200
D/FirebaseCrashSenderServiceImpl: Report sent


You can check the Crash reports on Console by logging into https://console.firebase.google.com in crash reports will look like this








Cheers!!

References :
https://firebase.google.com/docs/android

Monday, 21 March 2016

Method to add events from your Android App to default Calendar application



Please pass required parameters to the below method in order add events to default Calendar in android . 

Add Calendar and Accounts permission to manifest. And Also ask for Calendar Runtime permission for 6.0.

 Accounts permission is normal permission so Runtime implementation for same is not required.

 1. Manifest File

<uses-permission android:name="android.permission.GET_ACCOUNTS"/> <uses-permission android:name="android.permission.READ_CALENDAR"/> <uses-permission android:name="android.permission.WRITE_CALENDAR"/>
2. Methods to add event to Calendar (Modify as per need)

//here you can pass a model class which will contains all your values instead of many parameters

private void addEventToCalendar(Activity activity,String title,String startDateStr,String startTime, String endDateStr,String endTime,String eventDescription) { //Getting google accounts linked here Account[] accounts = AccountManager.get(activity).getAccountsByType( "com.google"); String accountName=""; for (Account acc : accounts) { Log.d(">>>>>>>", "Name: " + acc.name + "-----Type: " + acc.type); accountName = acc.name; } //Getting required calendar ID here long calID = getCalendarId(activity,accountName); long startMillis = 0; long endMillis = 0; Date startDate = null; //Converting date/time as per need try { startDate = new SimpleDateFormat("yyyy-MM-dd hh:mmaa", Locale.ENGLISH).parse(startDateStr+" "+startTime); } catch (ParseException e1) { e1.printStackTrace(); } startMillis = startDate.getTime(); Date endDate = null; try { endDate = new SimpleDateFormat("yyyy-MM-dd hh:mmaa", Locale.ENGLISH).parse(endDateStr+" "+endTime); } catch (ParseException e) { e.printStackTrace(); } endMillis = endDate.getTime(); //Creating content values which will be used to enter data from a query into calendar content resolver ContentResolver cr = activity.getContentResolver(); ContentValues values = new ContentValues(); values.put(CalendarContract.Events.DTSTART, startMillis); values.put(CalendarContract.Events.DTEND, endMillis); values.put(CalendarContract.Events.TITLE, title); values.put(CalendarContract.Events.DESCRIPTION,eventDescription); values.put(CalendarContract.Events.CALENDAR_ID, calID); values.put(CalendarContract.Events.EVENT_TIMEZONE, Calendar.getInstance().getTimeZone().getDisplayName()); try { // Executing query to enter event into the calendar here Uri uri = cr.insert(CalendarContract.Events.CONTENT_URI, values); } catch(Exception e) { e.printStackTrace(); } } private static long getCalendarId(Activity activity,String MY_ACCOUNT_NAME) { String[] projection = new String[] { BaseColumns._ID }; String selection = CalendarContract.Calendars.ACCOUNT_NAME + " = ?"; String[] selArgs = new String[] { MY_ACCOUNT_NAME }; Cursor cursor = activity.getContentResolver().query( CalendarContract.Calendars.CONTENT_URI, projection, selection, selArgs, null); if (cursor.moveToFirst()) { return cursor.getLong(0); } return -1; }


References : http://developer.android.com/index.html

Thursday, 31 December 2015

What are Normal permissions in Android?

There are two types of permissions:-

1. Normal permissions 
2. Runtime Permissions

We are familiar with Runtime permissions, here we will be discussing about Normal Permissions.
Normal permissions are the permissions which are automatically granted during install time. We need not to check these in our code(i.e runtime).And these are the permissions which user can not revoke from app settings as well.
We simply declare these permissions in the Android Manifest.xml and it will work nomally as did earlier.
.
Below is the list of permissions :-

android.permission.WRITE_SYNC_SETTINGS
com.android.alarm.permission.SET_ALARM
com.android.launcher.permission.INSTALL_SHORTCUT
com.android.launcher.permission.UNINSTALL_SHORTCUT
android.permission.ACCESS_WIMAX_STATE
android.permission.BLUETOOTH
android.permission.BLUETOOTH_ADMIN
android.permission.BROADCAST_STICKY
android.permission.CHANGE_NETWORK_STATE
android.permission.CHANGE_WIFI_MULTICAST_STATE
android.permission.CHANGE_WIFI_STATE
android.permission.CHANGE_WIMAX_STATE
android.permission.DISABLE_KEYGUARD
android.permission.EXPAND_STATUS_BAR
android.permission.ACCESS_LOCATION_EXTRA_COMMANDS
android.permission.ACCESS_NETWORK_STATE
android.permission.ACCESS_NOTIFICATION_POLICY
android.permission.ACCESS_WIFI_STATE
android.permission.FLASHLIGHT
android.permission.GET_ACCOUNTS
android.permission.GET_PACKAGE_SIZE
android.permission.INTERNET
android.permission.READ_SYNC_STATS
android.permission.RECEIVE_BOOT_COMPLETED
android.permission.REORDER_TASKS
android.permission.REQUEST_INSTALL_PACKAGES
android.permission.KILL_BACKGROUND_PROCESSES
android.permission.MODIFY_AUDIO_SETTINGS
android.permission.NFC
android.permission.SET_WALLPAPER_HINTS
android.permission.SUBSCRIBED_FEEDS_READ
android.permission.TRANSMIT_IR
android.permission.USE_FINGERPRINT
android.permission.VIBRATE
android.permission.WAKE_LOCK
android.permission.READ_SYNC_SETTINGS
android.permission.SET_TIME_ZONE
android.permission.SET_WALLPAPER

Sunday, 6 December 2015

Download/Upload files using Dropbox Api Android

This tutorial is about Downloading/Uploading files from/to Dropbox using DropboxApi Android.


Firstly create your App key and App Secret key to use this api from below link.
Dropbox App Console : https://www.dropbox.com/developers-v1/apps

Include the below jars files from the downloaded Dropbox Sdk :
1. dropbox-android-sdk-1.6.3.jar
2. json_simple-1.1.jar

1. MainActivity.java

public class MainActivity extends AppCompatActivity {

        //path of the file to be uploaded here    
String path= Environment.getExternalStorageDirectory()
            .getAbsolutePath() + "/photo.jpg";
    final static private String APP_KEY = "";
    final static private String APP_SECRET = "";
    private DropboxAPI<AndroidAuthSession> mDBApi;
    DropboxAPI.Entry response;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        /**
         *   i am using this mode . you can use the Async task to upload and download file
         */
        StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
        StrictMode.setThreadPolicy(policy);
        setContentView(R.layout.activity_main);
        //Generate dropbox session from the generated keys
        AppKeyPair appKeys = new AppKeyPair(APP_KEY, APP_SECRET);
        AndroidAuthSession session = new AndroidAuthSession(appKeys);
        mDBApi = new DropboxAPI<AndroidAuthSession>(session);
        //Check if user has already authorized the dropbox app for you..
        if(!getAccessToken().equalsIgnoreCase("")){
            mDBApi.getSession().setOAuth2AccessToken(getAccessToken());
        }else{
            //if not authorized. i.e for the first time then
            mDBApi = new DropboxAPI<AndroidAuthSession>(session);
            mDBApi.getSession().startOAuth2Authentication(MainActivity.this);
        }

        ((Button) findViewById(R.id.uploaddata)).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                uploadFile(path);
            }
        });

        ((Button) findViewById(R.id.downloadfile)).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                downloadFile(Environment.getExternalStorageDirectory()
                        .getAbsolutePath());
            }
        });
    }

    protected void onResume() {
        super.onResume();
        //if first time and save the Access Token here
        if(getAccessToken().equalsIgnoreCase("")) {
            if (mDBApi.getSession().authenticationSuccessful()) {
                try {
                    // Required to complete auth, sets the access token on the session
                    mDBApi.getSession().finishAuthentication();
                    String accessToken = mDBApi.getSession().getOAuth2AccessToken();
                    saveAccessToken(accessToken);
                } catch (IllegalStateException e) {
                    Log.i("Error", "Error authenticating", e);
                }
            }
        }
    }

    private void saveAccessToken(String accessToken){
        SharedPreferences sharedPreferences=getSharedPreferences("Prefs", Context.MODE_PRIVATE);
        sharedPreferences.edit().putString("accessToken", accessToken).commit();
    }

    private String getAccessToken(){
        SharedPreferences sharedPreferences=getSharedPreferences("Prefs", Context.MODE_PRIVATE);
        return sharedPreferences.getString("accessToken","");
    }

    public void uploadFile(String file_path) {
        File file = new File(file_path);
        FileInputStream inputStream = null;
        try {
            inputStream = new FileInputStream(file);
        } catch (FileNotFoundException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }
        try {
            response = mDBApi.putFile("/photo.jpg", inputStream,
                    file.length(), null, null);
            if(response.rev!=null){
                Toast.makeText(this,"File Uploaded successfully..",Toast.LENGTH_LONG).show();
            }
            Log.i("Success", "The uploaded file's rev is: " + response.rev);
        } catch (DropboxException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    public void downloadFile(String file_path) {
       //Path where you want to stored the downloaded file form dropbox
        File file = new File(file_path+"/testphoto.jpg");
        FileOutputStream outputStream = null;
        try {
            outputStream = new FileOutputStream(file);
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        DropboxAPI.DropboxFileInfo info = null;
        try {
            info = mDBApi.getFile("/photo.jpg", null, outputStream, null);
            if(info.getMetadata().rev!=null){
                Toast.makeText(this,"File Downloaded successfully..",Toast.LENGTH_LONG).show();
            }
            Log.i("Success", "The file's rev is: "
                    + info.getMetadata().rev);
        } catch (DropboxException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

2. Manifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.kamal.dropboxdemoapi" >
    <uses-permission android:name="android.permission.INTERNET"></uses-permission>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >

        <activity
            android:name="com.dropbox.client2.android.AuthActivity"
            android:launchMode="singleTask"
            android:configChanges="orientation|keyboard">
            <intent-filter>
                <!-- Change this to be db- followed by your app key -->
                <data android:scheme="db-Your App key here" />
                <action android:name="android.intent.action.VIEW" />
                <category android:name="android.intent.category.BROWSABLE"/>
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </activity>
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>


Find the source from  Github : https://github.com/CammyKamal/BlogTutorials/tree/master/DropBoxDemoApi