ca.mudar.mtlaucasou.LocationFragmentActivity.java Source code

Java tutorial

Introduction

Here is the source code for ca.mudar.mtlaucasou.LocationFragmentActivity.java

Source

/*
 * Copyright 2011 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/*
 * Modifications:
 * - Copied from radioactiveyak.location_best_practices
 * - Renamed package
 * - Removed Checkins functions
 */

package ca.mudar.mtlaucasou;

import ca.mudar.mtlaucasou.receivers.LocationChangedReceiver;
import ca.mudar.mtlaucasou.receivers.PassiveLocationChangedReceiver;
import ca.mudar.mtlaucasou.utils.ActivityHelper;
import ca.mudar.mtlaucasou.utils.AppHelper;
import ca.mudar.mtlaucasou.utils.Const;
import ca.mudar.mtlaucasou.utils.PlatformSpecificImplementationFactory;
import ca.mudar.mtlaucasou.utils.base.ILastLocationFinder;
import ca.mudar.mtlaucasou.utils.base.LocationUpdateRequester;

import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.location.Criteria;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.util.Log;

public class LocationFragmentActivity extends FragmentActivity {
    // TODO Refactor this into an abstract class

    private static final String TAG = "LocationFragmentActivity";

    protected int indexSection;

    protected AppHelper mAppHelper;
    protected ActivityHelper mActivityHelper;
    protected SharedPreferences prefs;
    protected SharedPreferences.Editor prefsEditor;

    protected Criteria criteria;
    protected ILastLocationFinder lastLocationFinder;
    protected LocationUpdateRequester locationUpdateRequester;
    protected PendingIntent locationListenerPendingIntent;
    protected PendingIntent locationListenerPassivePendingIntent;

    protected LocationManager locationManager;

    protected boolean hasRegisteredSingleUpdateReceiver = false;
    protected boolean hasRegisteredLocProviderDisabledReceiver = false;
    protected boolean hasFollowLocationChanges = false;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        mAppHelper = (AppHelper) getApplicationContext();
        mActivityHelper = ActivityHelper.createInstance(this);

        prefs = getSharedPreferences(Const.APP_PREFS_NAME, Context.MODE_PRIVATE);
        prefsEditor = prefs.edit();

        locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);

        /**
         * Instantiate a LastLocationFinder class. This will be used to find the
         * last known location when the application starts.
         */
        lastLocationFinder = PlatformSpecificImplementationFactory.getLastLocationFinder(this);
        lastLocationFinder.setChangedLocationListener(oneShotLastLocationUpdateListener);
        hasRegisteredSingleUpdateReceiver = true;

        /**
         * Set the last known location as user's current location.
         */
        mAppHelper.setLocation(lastLocationFinder.getLastBestLocation(Const.MAX_DISTANCE, Const.MAX_TIME));

        /**
         * Specify the Criteria to use when requesting location updates while
         * the application is Active.
         */
        criteria = new Criteria();
        if (Const.USE_GPS_WHEN_ACTIVITY_VISIBLE) {
            criteria.setAccuracy(Criteria.ACCURACY_FINE);
        } else {
            criteria.setPowerRequirement(Criteria.POWER_LOW);
        }

        /**
         * Setup the location update Pending Intents.
         */
        Intent activeIntent = new Intent(this, LocationChangedReceiver.class);
        locationListenerPendingIntent = PendingIntent.getBroadcast(this, 0, activeIntent,
                PendingIntent.FLAG_UPDATE_CURRENT);

        Intent passiveIntent = new Intent(this, PassiveLocationChangedReceiver.class);
        locationListenerPassivePendingIntent = PendingIntent.getBroadcast(this, 0, passiveIntent,
                PendingIntent.FLAG_UPDATE_CURRENT);
        locationManager.removeUpdates(locationListenerPassivePendingIntent);

        /**
         * Instantiate a Location Update Requester class based on the available
         * platform version. This will be used to request location updates.
         */
        locationUpdateRequester = PlatformSpecificImplementationFactory
                .getLocationUpdateRequester(this.getApplicationContext(), locationManager);

        super.onCreate(savedInstanceState);
    }

    @Override
    public void onResume() {
        /**
         * Commit shared preference that says we're in the foreground.
         */
        prefsEditor.putBoolean(Const.EXTRA_KEY_IN_BACKGROUND, false);
        prefsEditor.commit();

        /**
         * Get the last known location (and optionally request location updates)
         * and update the place list.
         */
        hasFollowLocationChanges = prefs.getBoolean(Const.PrefsNames.FOLLOW_LOCATION_CHANGES, false);
        getLocationAndUpdateCursor(hasFollowLocationChanges);

        super.onResume();
    }

    @Override
    protected void onPause() {
        prefsEditor.putBoolean(Const.EXTRA_KEY_IN_BACKGROUND, true);
        prefsEditor.commit();

        /**
         * Stop listening for location updates when the Activity is inactive.
         */
        disableLocationUpdates();

        super.onPause();
    }

    @Override
    protected void onDestroy() {
        if (hasRegisteredSingleUpdateReceiver) {
            lastLocationFinder.cancel();
        }

        if (Const.DISABLE_PASSIVE_LOCATION_WHEN_USER_EXIT) {
            locationManager.removeUpdates(locationListenerPassivePendingIntent);
        }

        super.onDestroy();
    }

    /**
     * Find the last known location (using a {@link LastLocationFinder}) and
     * updates the place list accordingly.
     * 
     * @param updateWhenLocationChanges Request location updates
     */
    protected void getLocationAndUpdateCursor(boolean updateWhenLocationChanges) {
        /**
         * This isn't directly affecting the UI, so put it on a worker thread.
         */
        AsyncTask<Void, Void, Void> findLastLocationTask = new AsyncTask<Void, Void, Void>() {
            @Override
            protected Void doInBackground(Void... params) {
                /**
                 * Find the last known location, specifying a required accuracy
                 * of within the min distance between updates and a required
                 * latency of the minimum time required between updates.
                 */
                Location lastKnownLocation = lastLocationFinder.getLastBestLocation(Const.MAX_DISTANCE,
                        System.currentTimeMillis() - Const.MAX_TIME);

                if (lastKnownLocation != null) {
                    mAppHelper.setLocation(lastKnownLocation);
                }

                return null;
            }
        };
        findLastLocationTask.execute();

        /**
         * If we have requested location updates, turn them on here.
         */
        toggleUpdatesWhenLocationChanges(updateWhenLocationChanges);
    }

    /**
     * Choose if we should receive location updates.
     * 
     * @param updateWhenLocationChanges Request location updates
     */
    protected void toggleUpdatesWhenLocationChanges(boolean updateWhenLocationChanges) {
        if (updateWhenLocationChanges) {
            requestLocationUpdates();
        } else {
            disableLocationUpdates();
        }
    }

    /**
     * Start listening for location updates.
     */
    protected void requestLocationUpdates() {
        hasRegisteredSingleUpdateReceiver = true;
        hasRegisteredLocProviderDisabledReceiver = true;

        /**
         * Normal updates while activity is visible.
         */
        locationUpdateRequester.requestLocationUpdates(Const.MAX_TIME, Const.MAX_DISTANCE, criteria,
                locationListenerPendingIntent);
        /**
         * Passive location updates from 3rd party apps when the Activity isn't
         * visible.
         */
        locationUpdateRequester.requestPassiveLocationUpdates(Const.PASSIVE_MAX_TIME, Const.PASSIVE_MAX_DISTANCE,
                locationListenerPassivePendingIntent);
        /**
         * Register a receiver that listens for when the provider I'm using has
         * been disabled.
         */
        IntentFilter intentFilter = new IntentFilter(Const.ACTIVE_LOCATION_UPDATE_PROVIDER_DISABLED);
        registerReceiver(locProviderDisabledReceiver, intentFilter);

        /**
         * Register a receiver that listens for when a better provider than I'm
         * using becomes available.
         */
        String bestProvider = locationManager.getBestProvider(criteria, false);
        String bestAvailableProvider = locationManager.getBestProvider(criteria, true);
        if (bestProvider != null && !bestProvider.equals(bestAvailableProvider)) {
            locationManager.requestLocationUpdates(bestProvider, 0, 0, bestInactiveLocationProviderListener,
                    getMainLooper());
        }
    }

    /**
     * Stop listening for location updates
     */
    protected void disableLocationUpdates() {
        if (hasRegisteredLocProviderDisabledReceiver) {
            hasRegisteredLocProviderDisabledReceiver = false;
            try {
                unregisterReceiver(locProviderDisabledReceiver);
            } catch (IllegalArgumentException e) {
                Log.v(TAG, "Receiver already unregistered. " + e.getMessage());
            }
        }

        locationManager.removeUpdates(locationListenerPendingIntent);
        locationManager.removeUpdates(bestInactiveLocationProviderListener);

        /**
         * When disabling active listeners, enable the passive listener
         * (according to user Preferences).
         */
        if (hasFollowLocationChanges) {
            locationUpdateRequester.requestPassiveLocationUpdates(Const.PASSIVE_MAX_TIME,
                    Const.PASSIVE_MAX_DISTANCE, locationListenerPassivePendingIntent);
        } else {
            locationManager.removeUpdates(locationListenerPassivePendingIntent);
        }
    }

    /**
     * One-off location listener that receives updates from the
     * {@link LastLocationFinder}. This is triggered where the last known
     * location is outside the bounds of our maximum distance and latency.
     */
    protected LocationListener oneShotLastLocationUpdateListener = new LocationListener() {
        public void onLocationChanged(Location l) {
            mAppHelper.setLocation(l);

            if (hasRegisteredSingleUpdateReceiver) {
                lastLocationFinder.cancel();
                hasRegisteredSingleUpdateReceiver = false;
            }
        }

        public void onProviderDisabled(String provider) {
        }

        public void onStatusChanged(String provider, int status, Bundle extras) {
        }

        public void onProviderEnabled(String provider) {
        }
    };

    /**
     * If the best Location Provider (usually GPS) is not available when we
     * request location updates, this listener will be notified if / when it
     * becomes available. It calls requestLocationUpdates to re-register the
     * location listeners using the better Location Provider.
     */
    protected LocationListener bestInactiveLocationProviderListener = new LocationListener() {
        public void onLocationChanged(Location l) {
        }

        public void onProviderDisabled(String provider) {
        }

        public void onStatusChanged(String provider, int status, Bundle extras) {
        }

        public void onProviderEnabled(String provider) {
            /**
             * Re-register the location listeners using the better
             * Location Provider.
             */
            requestLocationUpdates();
        }
    };

    /**
     * If the Location Provider we're using to receive location updates is
     * disabled while the app is running, this Receiver will be notified,
     * allowing us to re-register our Location Receivers using the best
     * available Location Provider is still available.
     */
    protected BroadcastReceiver locProviderDisabledReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            boolean providerDisabled = !intent.getBooleanExtra(LocationManager.KEY_PROVIDER_ENABLED, false);
            /**
             * Re-register the location listeners using the best
             * available Location Provider.
             */
            if (providerDisabled)
                requestLocationUpdates();
        }
    };
}