April 14, 2019

Android Location Tracking In Using Service

             
                                  On this Blog I am going to explain about location update when the applications is running on background. In some cases we need to send location updated to our server when the application is on background. For this I am using startForeground() function.  

     Here LocationService.java is my Service Class which I used to get the location update on Background.


LocationService.java

public class LocationService extends Service implements LocationListener, GoogleApiClient.ConnectionCallbacks,
        GoogleApiClient.OnConnectionFailedListener {
    LocationRequest mLocationRequest;
    GoogleApiClient mGoogleApiClient;

    private static final String TAG = "LocationService";
    private static final int LOCATION_INTERVAL = 10000;
    private static final int FASTEST_INTERVAL = 10000;
    @Override
    public void onCreate() {

        if (isGooglePlayServicesAvailable()) {
            mLocationRequest = new LocationRequest();
            mLocationRequest.setInterval(LOCATION_INTERVAL);
            mLocationRequest.setFastestInterval(FASTEST_INTERVAL);
            mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
            //mLocationRequest.setSmallestDisplacement(10.0f);  /* min dist for location change, here it is 10 meter */
            mGoogleApiClient = new GoogleApiClient.Builder(this)
                    .addApi(LocationServices.API)
                    .addConnectionCallbacks(this)
                    .addOnConnectionFailedListener(this)
                    .build();

            mGoogleApiClient.connect();
        }
    }

    //Check Google play is available or not
    private boolean isGooglePlayServicesAvailable() {
        int status = GooglePlayServicesUtil.isGooglePlayServicesAvailable(getApplicationContext());
        return ConnectionResult.SUCCESS == status;
    }

    @Override
    public void onConnected(Bundle bundle) {
        Log.d(TAG, "Connected");
        startLocationUpdates();
    }

    @Override
    public void onConnectionSuspended(int i) {
        Log.d(TAG, "Connection suspended");
    }

    protected void startLocationUpdates() {
        Log.d(TAG, "Start Location Updates");
        try {
            int permissionCheck = ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION);
            if (permissionCheck == PackageManager.PERMISSION_GRANTED) {
                LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);
            }
        } catch (IllegalStateException e) {
        }
    }


    @Override
    public void onLocationChanged(Location location) {
        if (location != null) {
            Log.d(TAG, "Location Changed: " + location.getLatitude() + "," + location.getLongitude());
            //Send Broadcast
            Intent intent = new Intent(getPackageName());
            intent.putExtra(Constants.LocationUpdated, location);
            sendBroadcast(intent);
        }

    }


   /* LocationListener[] mLocationListeners = new LocationListener[]{
            new LocationListener(LocationManager.GPS_PROVIDER),
            new LocationListener(LocationManager.NETWORK_PROVIDER)
    };*/


    @Override
    public IBinder onBind(Intent arg0) {
        return null;
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        super.onStartCommand(intent, flags, startId);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            Notification.Builder builder = new Notification.Builder(this, Constants.LOCATION_CHANNEL_ID)
                    .setContentTitle(getString(R.string.app_name))
                    .setContentText(Constants.LocationChange)
                    .setAutoCancel(true);

            Notification notification = builder.build();
            startForeground(1, notification);
        } else {
             NotificationCompat.Builder builder = new NotificationCompat.Builder(this)
                    .setContentTitle(getString(R.string.app_name))
                    .setContentText(Constants.LocationChange)
                    .setPriority(NotificationCompat.PRIORITY_DEFAULT)
                    .setAutoCancel(true);
            Notification notification = builder.build();
            startForeground(1, notification);
        }
        return START_NOT_STICKY;
    }


    @Override
    public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
        Log.d(TAG, "onConnectionFailed:: " + connectionResult.getErrorMessage());
    }
}


Once you create the Service Class you need to add this service class to AndroidManifest.xml file, Also You need to add the Location permissions if you didn't added on your Manifest file, Here is my Manifest file,

AndroidManifest.xml 

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

    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.INTERNET" />
    <permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.WAKE_LOCK" />

    <application
        android:name=".AppController"
        android:allowBackup="true"
        android:hardwareAccelerated="false"
        android:icon="@drawable/logo_squre"
        android:label="@string/app_name"
        android:largeHeap="true"
        android:launchMode="singleInstance"
        android:roundIcon="@drawable/logo_circle"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity
            android:name=".HomeActivity"
            android:screenOrientation="portrait">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <service android:name=".service.LocationService" />
    </application>

</manifest>


On the next step you need to create the Notification channel on your application class. We are using createNotificationChannel()method to Create Notification channel, Here us my Application class,


AppController.java


public class AppController extends Application {

    public static final String TAG = AppController.class.getSimpleName();

    @Override
    public void onCreate() {
        super.onCreate();
        mInstance = this;
        createNotificationChannel();
    }

    @Override
    protected void attachBaseContext(Context base) {
        super.attachBaseContext(base);
        MultiDex.install(this);
    }

    public static synchronized AppController getInstance() {
        return mInstance;
    }


    private void createNotificationChannel() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationChannel serviceChannel = new NotificationChannel(
                    Constants.LOCATION_CHANNEL_ID,
                    getString(R.string.app_name),
                    NotificationManager.IMPORTANCE_DEFAULT
            );

            NotificationManager manager = getSystemService(NotificationManager.class);
            manager.createNotificationChannel(serviceChannel);
        }
    }

}


Next step is to integrate the service class on our Activity class. To handle the broadcast we need to register the Broadcast Receiver on the Activity class. Here I am going to use createBroadcastReceiver() method for Register the Broadcast Receiver.  This method will Invoke in  onCreate(Bundle savedInstanceState) method like,  Here is my method for register the receiver,


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_home);

            //To Register the Receiver 
            broadcastReceiver = createBroadcastReceiver();
            registerReceiver(broadcastReceiver, new IntentFilter(getPackageName()));
    }


    //Method for Register Broadcast receiver 
    private BroadcastReceiver createBroadcastReceiver() {
        return new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                if (intent != null) {
                    if (intent.hasExtra(Constants.LocationUpdated)){
                        Location location = AppController.getInstance().getCurrentLocation();
                        if (location != null) {
                            Log.e("Broadcast: ", "New Location: " + location.getLatitude() + "," + location.getLongitude());
                          
                        }
                    }
                }
            }
        };

    }


To start and stop the location location service am using startLocationService()  and stopLocationService() method. 

    //Service Intent Decleration 
    Intent locationServiceIntent;


    //Start Location Service
    public void startLocationService() {
        if (locationServiceIntent == null)
            locationServiceIntent = new Intent(this, LocationService.class);
        if (!Helper.isServiceRunning(HomeActivity.this, LocationService.class)) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                startForegroundService(locationServiceIntent);
            } else {
                startService(locationServiceIntent);
            }
        }
    }


    //Stop Location service
    public void stopLocationService() {
        if (locationServiceIntent != null && Helper.isServiceRunning(HomeActivity.this, LocationService.class))
            stopService(locationServiceIntent);
    }






---------------
Thanks For Reading, Wish you a Happy Coding....


















April 04, 2019

How to get Notification on Back Stack Change On android

            On this blog I am going to explain How to we can get notification on the fragment change on our Activity Class. In Some Cases we need to get the notification when the fragment is changed. We are using OnBackStackChangedListener for this. Here is the way we are doing it,


First we need to add the Listener on onCreate method of Activity Class . For this I have Created a function addPopBackStackListener(). Here is the way we initializing the  Listener

         @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_home);
        
        addPopBackStackListener();


   }

Here is my addPopBackStackListener() function,

   private void addPopBackStackListener() {
        getSupportFragmentManager().addOnBackStackChangedListener(
            new FragmentManager.OnBackStackChangedListener() {
                public void onBackStackChanged() {
                    FragmentManager fragmentManager = getSupportFragmentManager();
                    if (fragmentManager != null && fragmentManager.getFragments() != null) {                   
                    int count = fragmentManager.getFragments().size();
                        if (count > 0) {
                            Fragment fragment = fragmentManager.getFragments().get(count- 1);
                               
                            Log.v(TAG, "Class: " + fragment.getClass().getSimpleName());

                            /* Using instanceof keyword you can find out which fragment is loaded*/
                            if (fragment instanceof HomeFragment) {
                                 /*Add your code to Perform Action when Home Fragment is Loaded*/  

                            } 
                           
                        }
                    }                 
                }
            });
    }



---------------
Thanks For Reading, Wish you a Happy Coding....