com.nicolatesser.geofencedemo.LocationActivity.java Source code

Java tutorial

Introduction

Here is the source code for com.nicolatesser.geofencedemo.LocationActivity.java

Source

/*
 * Copyright (C) 2013 The Android Open Source Project
 *
 * 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.
 */
package com.nicolatesser.geofencedemo;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import android.app.Dialog;
import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.Configuration;
import android.graphics.Color;
import android.location.Location;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MenuItem.OnMenuItemClickListener;
import android.view.View;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.Switch;
import android.widget.TextView;

import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GooglePlayServicesClient.ConnectionCallbacks;
import com.google.android.gms.common.GooglePlayServicesClient.OnConnectionFailedListener;
import com.google.android.gms.common.GooglePlayServicesUtil;
import com.google.android.gms.location.ActivityRecognitionClient;
import com.google.android.gms.location.Geofence;
import com.google.android.gms.location.LocationClient;
import com.google.android.gms.location.LocationClient.OnAddGeofencesResultListener;
import com.google.android.gms.location.LocationClient.OnRemoveGeofencesResultListener;
import com.google.android.gms.location.LocationListener;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationStatusCodes;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.GoogleMap.OnMapLongClickListener;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.CameraPosition;
import com.google.android.gms.maps.model.Circle;
import com.google.android.gms.maps.model.CircleOptions;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.MarkerOptions;

public class LocationActivity extends FragmentActivity {
    public static String TAG = "LocationActivity";
    public static boolean isAppForeground = false;
    private static final int ERROR_DIALOG_ON_CREATE_REQUEST_CODE = 4055;
    private static final int ERROR_DIALOG_ON_RESUME_REQUEST_CODE = 4056;

    // Shared variables
    private GoogleMap mMap;
    private Dialog errorDialog;

    // Location Request variables
    private LocationClient mLocationClient;
    private TextView mLocationStatus;
    private LocationCallback mLocationCallback = new LocationCallback();
    private Location mLastLocation;
    private final int LOCATION_UPDATES_INTERVAL = 2000; // Setting 2 sec
    // interval for
    // location updates

    // Activity Recognition variables
    private ActivityRecognitionClient mActivityRecognitionClient;
    private ActivityRecognitionCallback mActivityRecognitionCallback = new ActivityRecognitionCallback();
    public static final String ACTION_ACTIVITY_RECOGNITION = "com.nicolatesser.geofencedemo.ACTIVITY_RECOGNITION";
    private static final int ACTIVITY_UPDATES_INTERVAL = 2000;
    private PendingIntent mActivityRecognitionPendingIntent;
    private Switch mSwitch;
    private ActivityRecognitionIntentReceiver mActivityRecognitionIntentReceiver;

    // Geo Fencing variables
    private GeoFenceCallback mGeoFenceCallback = new GeoFenceCallback();
    private int id = 0;
    private static final float GEOFENCE_RADIUS = 50;
    private HashMap<String, Circle> mGeoFences;
    private HashMap<String, Circle> mTriggeringFences;
    private TextView mGeoFenceStatus;
    public static final String ACTION_GEOFENCE = "com.android.google.codelab.location.LocationActivity.GEOFENCE";

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        checkGooglePlayServiceAvailability(ERROR_DIALOG_ON_CREATE_REQUEST_CODE);
    }

    private void init() {
        // Initialize map
        if (mMap == null) {
            FragmentManager myFragmentManager = getSupportFragmentManager();
            SupportMapFragment myMapFragment = (SupportMapFragment) myFragmentManager.findFragmentById(R.id.map);
            mMap = myMapFragment.getMap();
        }

        // Initialize Location Client
        mLocationStatus = (TextView) findViewById(R.id.location_status);

        if (mLocationClient == null) {
            mLocationClient = new LocationClient(this, mLocationCallback, mLocationCallback);
            Log.v(LocationActivity.TAG, "Location Client connect");
            if (!(mLocationClient.isConnected() || mLocationClient.isConnecting())) {
                mLocationClient.connect();
            }
        }

        // Initialize Action Recognition
        if (mActivityRecognitionClient == null) {
            mActivityRecognitionClient = new ActivityRecognitionClient(this, mActivityRecognitionCallback,
                    mActivityRecognitionCallback);
        }
        mSwitch = (Switch) findViewById(R.id.swtich);
        stopActivityDetection(mSwitch);
        mSwitch.setOnCheckedChangeListener(new OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                if (isChecked) {
                    startActivityDetection(buttonView);
                } else {
                    stopActivityDetection(buttonView);
                }
            }
        });
        if (mActivityRecognitionIntentReceiver == null) {
            mActivityRecognitionIntentReceiver = new ActivityRecognitionIntentReceiver();
            registerReceiver(mActivityRecognitionIntentReceiver,
                    new IntentFilter(LocationActivity.ACTION_ACTIVITY_RECOGNITION));
        }

        // Initialize Geo Fencing
        mGeoFenceStatus = (TextView) findViewById(R.id.geo_fence_status);

        if (mGeoFences == null) {
            mGeoFences = new HashMap<String, Circle>();

            // add Seitenbau Gmbh;
            addGeoFence("SEITENBAU", new LatLng(47.670417, 9.155700));
            //addGeoFence("HOME", new LatLng(47.672872, 9.170997));
            addGeoFence("WASSERTURM", new LatLng(47.67029, 9.154609));

        }

        if (mTriggeringFences == null) {
            mTriggeringFences = new HashMap<String, Circle>();
        }

        // Setup map to allow adding Geo Fences
        mMap.getUiSettings().setAllGesturesEnabled(true);
        mMap.setOnMapLongClickListener(mGeoFenceCallback);

    }

    private void addGeoFence(String key, LatLng point) {
        CircleOptions circleOptions = new CircleOptions();
        circleOptions.center(point).radius(GEOFENCE_RADIUS).strokeColor(android.graphics.Color.BLUE).strokeWidth(2);
        Circle circle = mMap.addCircle(circleOptions);
        id++;
        mGeoFences.put(key, circle);
    }

    @Override
    public void onPause() {
        super.onPause();

        // Indicate the application is in background
        isAppForeground = false;

        if (mLocationClient.isConnected()) {
            mLocationClient.removeLocationUpdates(mLocationCallback);
            mLocationClient.disconnect();
        }
    }

    @Override
    public void onResume() {
        super.onResume();

        // Indicate the application is in foreground
        isAppForeground = true;

        checkGooglePlayServiceAvailability(ERROR_DIALOG_ON_RESUME_REQUEST_CODE);

        restartLocationClient();
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        unregisterReceiver(mActivityRecognitionIntentReceiver);
        mActivityRecognitionIntentReceiver = null;
    }

    private void checkGooglePlayServiceAvailability(int requestCode) {
        // Query for the status of Google Play services on the device
        int statusCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(getBaseContext());

        if (statusCode == ConnectionResult.SUCCESS) {
            init();
        } else {
            if (GooglePlayServicesUtil.isUserRecoverableError(statusCode)) {
                errorDialog = GooglePlayServicesUtil.getErrorDialog(statusCode, this, requestCode);
                errorDialog.show();
            } else {
                // Handle unrecoverable error
            }
        }
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (resultCode == RESULT_OK) {
            switch (requestCode) {
            case ERROR_DIALOG_ON_CREATE_REQUEST_CODE:
                init();
                break;
            case ERROR_DIALOG_ON_RESUME_REQUEST_CODE:
                restartLocationClient();
                break;
            }
        }
    }

    private void restartLocationClient() {
        if (!(mLocationClient.isConnected() || mLocationClient.isConnecting())) {
            mLocationClient.connect(); // Somehow it becomes connected here
            return;
        }

        if (mLocationClient.isConnecting()) {
            return;
        }

        LocationRequest request = LocationRequest.create();
        request.setInterval(LOCATION_UPDATES_INTERVAL);
        request.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
        mLocationClient.requestLocationUpdates(request, mLocationCallback);
    }

    @SuppressWarnings("unused")
    private void codeForThePresentation() {

        OnConnectionFailedListener connectionFailedListener = new OnConnectionFailedListener() {

            @Override
            public void onConnectionFailed(ConnectionResult arg0) {
                // TODO Auto-generated method stub

            }
        };
        ConnectionCallbacks connectionCallback = new ConnectionCallbacks() {

            @Override
            public void onDisconnected() {
                // TODO Auto-generated method stub

            }

            @Override
            public void onConnected(Bundle arg0) {
                // TODO Auto-generated method stub

            }
        };

        // Instantiate a Location Client
        LocationClient mLocationClient = new LocationClient(this, connectionCallback, connectionFailedListener);
        mLocationClient.connect();

        /* ... After the onConnected method of the connectionCallback */

        // Get the latest known location. Useful when you need location quickly.
        Location location = mLocationClient.getLastLocation();

        // Create location request.
        LocationRequest locationRequest = LocationRequest.create().setInterval(5000)
                .setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY); // LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY
        // LocationRequest.PRIORITY_NO_POWER
        // LocationRequest.PRIORITY_LOW_POWER

        LocationListener mLocationListener = new LocationListener() {

            public void onLocationChanged(Location location) {
                Log.i(TAG, "Received a new location " + location);
            }
        };

        // Request updates.
        mLocationClient.requestLocationUpdates(locationRequest, mLocationListener);

        LocationRequest request = LocationRequest.create();
        request.setInterval(LOCATION_UPDATES_INTERVAL);
        request.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
        mLocationClient.requestLocationUpdates(request, mLocationCallback);

    }

    public void startActivityDetection(View v) {
        if (!mActivityRecognitionClient.isConnected()) {
            mActivityRecognitionClient.connect();
        }
    }

    public void stopActivityDetection(View v) {
        if (mActivityRecognitionClient.isConnected()) {
            mActivityRecognitionClient.removeActivityUpdates(mActivityRecognitionPendingIntent);
            mActivityRecognitionClient.disconnect();
        }
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        MenuItem menuItem = menu.add(R.string.clear_map);
        menuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
        menuItem.setOnMenuItemClickListener(new OnMenuItemClickListener() {
            @Override
            public boolean onMenuItemClick(MenuItem item) {
                clearMap();
                return true;
            }
        });
        return true;
    }

    public void clearMap() {
        mMap.clear();
        mLastLocation = null;
        mGeoFenceCallback.removeGeoFences();

    }

    private class LocationCallback implements ConnectionCallbacks, OnConnectionFailedListener, LocationListener {

        @Override
        public void onConnected(Bundle connectionHint) {
            Log.v(LocationActivity.TAG, "Location Client connected");

            // Display last location
            Location location = mLocationClient.getLastLocation();
            if (location != null) {
                handleLocation(location);
            }

            // Request for location updates
            LocationRequest request = LocationRequest.create();
            request.setInterval(LOCATION_UPDATES_INTERVAL);
            request.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
            mLocationClient.requestLocationUpdates(request, mLocationCallback);

            // Setup map to allow adding Geo Fences
        }

        @Override
        public void onDisconnected() {
            Log.v(LocationActivity.TAG, "Location Client disconnected by the system");
        }

        @Override
        public void onConnectionFailed(ConnectionResult result) {
            Log.v(LocationActivity.TAG, "Location Client connection failed");
        }

        @Override
        public void onLocationChanged(Location location) {
            if (location == null) {
                Log.v(LocationActivity.TAG, "onLocationChanged: location == null");
                return;
            }
            // Add a marker iff location has changed.
            if (mLastLocation != null && mLastLocation.getLatitude() == location.getLatitude()
                    && mLastLocation.getLongitude() == location.getLongitude()) {
                return;
            }

            handleLocation(location);
        }

        private void handleLocation(Location location) {
            // Update the mLocationStatus with the lat/lng of the location
            Log.v(LocationActivity.TAG,
                    "LocationChanged == @" + location.getLatitude() + "," + location.getLongitude());
            mLocationStatus.setText("Location changed @" + location.getLatitude() + "," + location.getLongitude());

            // Add a marker of that location to the map
            LatLng latlongzoom = new LatLng(location.getLatitude(), location.getLongitude());
            String snippet = location.getLatitude() + "," + location.getLongitude();
            Marker marker = mMap.addMarker(new MarkerOptions().position(latlongzoom));
            marker.setSnippet(snippet);
            marker.setTitle(snippet);

            // Center the map to the first marker
            if (mLastLocation == null) {
                mMap.moveCamera(CameraUpdateFactory.newCameraPosition(CameraPosition.fromLatLngZoom(
                        new LatLng(location.getLatitude(), location.getLongitude()), (float) 16.0)));
            }
            mLastLocation = location;
        }

    };

    private class ActivityRecognitionCallback implements ConnectionCallbacks, OnConnectionFailedListener {
        @Override
        public void onConnected(Bundle connectionHint) {
            Log.v(LocationActivity.TAG, "Activity Recognition Client Connected");
            // Request activity updates
            Intent intent = new Intent(LocationActivity.this, ActivityRecognitionIntentService.class);
            intent.setAction(LocationActivity.ACTION_ACTIVITY_RECOGNITION);
            mActivityRecognitionPendingIntent = PendingIntent.getService(LocationActivity.this, 0, intent,
                    PendingIntent.FLAG_UPDATE_CURRENT);
            mActivityRecognitionClient.requestActivityUpdates(ACTIVITY_UPDATES_INTERVAL,
                    mActivityRecognitionPendingIntent);
        }

        @Override
        public void onDisconnected() {
            Log.v(LocationActivity.TAG, "Activity Recognition Client Disconnected");
        }

        @Override
        public void onConnectionFailed(ConnectionResult result) {
            Log.v(LocationActivity.TAG, "Activity Recognition Client connection failed " + result.getErrorCode());
        }
    };

    private class GeoFenceCallback
            implements OnMapLongClickListener, OnAddGeofencesResultListener, OnRemoveGeofencesResultListener {

        @Override
        public void onMapLongClick(LatLng point) {
            Log.v(LocationActivity.TAG, "onMapLongClick == " + point.latitude + "," + point.longitude);

            CircleOptions circleOptions = new CircleOptions();
            circleOptions.center(point).radius(GEOFENCE_RADIUS).strokeColor(android.graphics.Color.BLUE)
                    .strokeWidth(2);
            Circle circle = mMap.addCircle(circleOptions);
            String key = Integer.toString(id);
            id++;
            mGeoFences.put(key, circle);
            addGeoFences();

        }

        private void addGeoFences() {
            List<Geofence> list = new ArrayList<Geofence>();
            for (Map.Entry<String, Circle> entry : mGeoFences.entrySet()) {
                Circle circle = entry.getValue();
                Log.v(LocationActivity.TAG,
                        "points == " + circle.getCenter().latitude + "," + circle.getCenter().longitude);
                Geofence geofence = new Geofence.Builder().setRequestId(entry.getKey())
                        .setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER | Geofence.GEOFENCE_TRANSITION_EXIT)
                        .setCircularRegion(circle.getCenter().latitude, circle.getCenter().longitude,
                                (float) circle.getRadius())
                        .setExpirationDuration(Geofence.NEVER_EXPIRE).build();
                list.add(geofence);
            }

            if (list.isEmpty()) {
                return;
            }

            // Clear off all the currently triggering geo_fences before new
            // fences
            // are added.
            for (Circle triggeringGeoFence : mTriggeringFences.values()) {
                triggeringGeoFence.remove();
            }
            mTriggeringFences.clear();
            Log.v(LocationActivity.TAG, "addingGeoFences size = " + list.size());
            mLocationClient.addGeofences(list, getPendingIntent(), this);
        }

        private PendingIntent getPendingIntent() {
            Intent intent = new Intent(ACTION_GEOFENCE);
            intent.setComponent(new ComponentName(LocationActivity.this, GeoFenceIntentReceiver.class));
            return PendingIntent.getBroadcast(LocationActivity.this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
        }

        @Override
        public void onAddGeofencesResult(int statusCode, String[] geofenceRequestIds) {
            StringBuilder builder = new StringBuilder();
            for (int i = 0; i < geofenceRequestIds.length - 1; ++i) {
                builder.append(geofenceRequestIds[i]);
                builder.append(",");
            }
            builder.append(geofenceRequestIds[geofenceRequestIds.length - 1]);
            Log.v(LocationActivity.TAG,
                    "Added Geofences == " + statusCodeToString(statusCode) + " " + builder.toString());
            mGeoFenceStatus.setText("Added Geofences " + statusCodeToString(statusCode) + " " + builder.toString());
        }

        private String statusCodeToString(int statusCode) {
            switch (statusCode) {
            case LocationStatusCodes.SUCCESS:
                return "SUCCESS";
            case LocationStatusCodes.GEOFENCE_NOT_AVAILABLE:
                return "GEOFENCE_NOT_AVAILABLE";
            case LocationStatusCodes.GEOFENCE_TOO_MANY_GEOFENCES:
                return "GEOFENCE_TOO_MANY_GEOFENCES";
            case LocationStatusCodes.GEOFENCE_TOO_MANY_PENDING_INTENTS:
                return "GEOFENCE_TOO_MANY_PENDING_INTENTS";
            case LocationStatusCodes.ERROR:
                return "ERROR";
            }
            return "UNKNOWN";
        }

        private void removeGeoFences() {
            List<String> requestIdsForRemoval = new ArrayList<String>();
            if (mGeoFences.isEmpty())
                return;
            for (Map.Entry<String, Circle> entry : mGeoFences.entrySet()) {
                String requestId = entry.getKey();
                Circle circle = entry.getValue();
                if (circle != null) {
                    circle.remove();
                    id--;
                    Log.v(LocationActivity.TAG, "RemoveGeoFence requestId == " + requestId);
                    Circle triggeringCircle = mTriggeringFences.get(requestId);
                    if (triggeringCircle != null) {
                        triggeringCircle.remove();
                    }
                    requestIdsForRemoval.add(requestId);
                }
            }
            mGeoFences.clear();
            mTriggeringFences.clear();
            mLocationClient.removeGeofences(requestIdsForRemoval, this);
        }

        @Override
        public void onRemoveGeofencesByPendingIntentResult(int statusCode, PendingIntent pendingIntent) {
            // Do nothing
        }

        @Override
        public void onRemoveGeofencesByRequestIdsResult(int statusCode, String[] geofenceRequestIds) {
            StringBuilder builder = new StringBuilder();
            for (int i = 0; i < geofenceRequestIds.length - 1; ++i) {
                builder.append(geofenceRequestIds[i]);
                builder.append(",");
            }
            builder.append(geofenceRequestIds[geofenceRequestIds.length - 1]);
            Log.v(LocationActivity.TAG,
                    "Removed Geofence " + statusCodeToString(statusCode) + " " + builder.toString());
            mGeoFenceStatus.setText(
                    "Removed Geofences request_ids = " + builder.toString() + " " + statusCodeToString(statusCode));
        }

    }

    // Triggered when startAcitivity method is called in GeoFenceIntentReceiver.
    // Updates UI as geofences are entered/exited.
    @Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);

        // getIntent() should always return the most recent
        setIntent(intent);

        boolean receiverStarted = intent.getBooleanExtra("RECEIVER_STARTED", false);

        if (!receiverStarted) {
            return;
        }

        Bundle bundle = intent.getParcelableExtra("geo_fences");
        ArrayList<String> requestIds = bundle.getStringArrayList("request_ids");

        if (requestIds == null) {
            Log.v(LocationActivity.TAG, "request_ids == null");
            return;
        }

        int transition = intent.getIntExtra("transition", -2);

        for (String requestId : requestIds) {
            Log.v(LocationActivity.TAG, "Triggering Geo Fence requestId " + requestId);
            if (transition == Geofence.GEOFENCE_TRANSITION_ENTER) {
                Circle circle = mGeoFences.get(requestId);
                if (circle == null) {
                    continue;
                }
                Log.v(LocationActivity.TAG, "triggering_geo_fences enter == " + requestId);

                // Add a superimposed red circle when a geofence is entered and
                // put the corresponding object in triggering_fences.
                CircleOptions circleOptions = new CircleOptions();
                circleOptions.center(circle.getCenter()).radius(circle.getRadius())
                        .fillColor(Color.argb(100, 100, 0, 0));
                Circle newCircle = mMap.addCircle(circleOptions);
                mTriggeringFences.put(requestId, newCircle);

                // LocationLoggerService.getInstance().writeActivity(
                // DemoConstant.NAME, "Entered in Geofence");

            } else if (transition == Geofence.GEOFENCE_TRANSITION_EXIT) {
                Log.v(LocationActivity.TAG, "triggering_geo_fences exit == " + requestId);
                Circle circle = mTriggeringFences.get(requestId);
                if (circle == null) {
                    continue;
                }
                // Remove the superimposed red circle from the map and the
                // corresponding Circle object from triggering_fences hash_map.
                circle.remove();
                mTriggeringFences.remove(requestId);

                // LocationLoggerService.getInstance().writeActivity(
                // DemoConstant.NAME, "Exited from Geofence");
            }
        }
        return;
    }

}