Home | History | Annotate | Download | only in geofencing
      1 /*
      2  * Copyright (C) 2014 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.example.android.wearable.geofencing;
     18 
     19 import static com.example.android.wearable.geofencing.Constants.ANDROID_BUILDING_ID;
     20 import static com.example.android.wearable.geofencing.Constants.ANDROID_BUILDING_LATITUDE;
     21 import static com.example.android.wearable.geofencing.Constants.ANDROID_BUILDING_LONGITUDE;
     22 import static com.example.android.wearable.geofencing.Constants.ANDROID_BUILDING_RADIUS_METERS;
     23 import static com.example.android.wearable.geofencing.Constants.CONNECTION_FAILURE_RESOLUTION_REQUEST;
     24 import static com.example.android.wearable.geofencing.Constants.GEOFENCE_EXPIRATION_TIME;
     25 import static com.example.android.wearable.geofencing.Constants.TAG;
     26 import static com.example.android.wearable.geofencing.Constants.YERBA_BUENA_ID;
     27 import static com.example.android.wearable.geofencing.Constants.YERBA_BUENA_LATITUDE;
     28 import static com.example.android.wearable.geofencing.Constants.YERBA_BUENA_LONGITUDE;
     29 import static com.example.android.wearable.geofencing.Constants.YERBA_BUENA_RADIUS_METERS;
     30 
     31 import android.app.Activity;
     32 import android.app.PendingIntent;
     33 import android.content.Intent;
     34 import android.content.IntentSender;
     35 import android.os.Bundle;
     36 import android.util.Log;
     37 import android.widget.Toast;
     38 
     39 import com.google.android.gms.common.ConnectionResult;
     40 import com.google.android.gms.common.api.GoogleApiClient.ConnectionCallbacks;
     41 import com.google.android.gms.common.GooglePlayServicesUtil;
     42 import com.google.android.gms.common.api.GoogleApiClient;
     43 import com.google.android.gms.common.api.GoogleApiClient.OnConnectionFailedListener;
     44 import com.google.android.gms.location.Geofence;
     45 import com.google.android.gms.location.LocationServices;
     46 
     47 import java.util.ArrayList;
     48 import java.util.List;
     49 
     50 public class MainActivity extends Activity implements ConnectionCallbacks,
     51         OnConnectionFailedListener {
     52 
     53     // Internal List of Geofence objects. In a real app, these might be provided by an API based on
     54     // locations within the user's proximity.
     55     List<Geofence> mGeofenceList;
     56 
     57     // These will store hard-coded geofences in this sample app.
     58     private SimpleGeofence mAndroidBuildingGeofence;
     59     private SimpleGeofence mYerbaBuenaGeofence;
     60 
     61     // Persistent storage for geofences.
     62     private SimpleGeofenceStore mGeofenceStorage;
     63 
     64     private LocationServices mLocationService;
     65     // Stores the PendingIntent used to request geofence monitoring.
     66     private PendingIntent mGeofenceRequestIntent;
     67     private GoogleApiClient mApiClient;
     68 
     69     // Defines the allowable request types (in this example, we only add geofences).
     70     private enum REQUEST_TYPE {ADD}
     71     private REQUEST_TYPE mRequestType;
     72 
     73     @Override
     74     protected void onCreate(Bundle savedInstanceState) {
     75         super.onCreate(savedInstanceState);
     76         // Rather than displayng this activity, simply display a toast indicating that the geofence
     77         // service is being created. This should happen in less than a second.
     78         if (!isGooglePlayServicesAvailable()) {
     79             Log.e(TAG, "Google Play services unavailable.");
     80             finish();
     81             return;
     82         }
     83 
     84         mApiClient = new GoogleApiClient.Builder(this)
     85                 .addApi(LocationServices.API)
     86                 .addConnectionCallbacks(this)
     87                 .addOnConnectionFailedListener(this)
     88                 .build();
     89 
     90         mApiClient.connect();
     91 
     92         // Instantiate a new geofence storage area.
     93         mGeofenceStorage = new SimpleGeofenceStore(this);
     94         // Instantiate the current List of geofences.
     95         mGeofenceList = new ArrayList<Geofence>();
     96         createGeofences();
     97     }
     98 
     99     /**
    100      * In this sample, the geofences are predetermined and are hard-coded here. A real app might
    101      * dynamically create geofences based on the user's location.
    102      */
    103     public void createGeofences() {
    104         // Create internal "flattened" objects containing the geofence data.
    105         mAndroidBuildingGeofence = new SimpleGeofence(
    106                 ANDROID_BUILDING_ID,                // geofenceId.
    107                 ANDROID_BUILDING_LATITUDE,
    108                 ANDROID_BUILDING_LONGITUDE,
    109                 ANDROID_BUILDING_RADIUS_METERS,
    110                 GEOFENCE_EXPIRATION_TIME,
    111                 Geofence.GEOFENCE_TRANSITION_ENTER | Geofence.GEOFENCE_TRANSITION_EXIT
    112         );
    113         mYerbaBuenaGeofence = new SimpleGeofence(
    114                 YERBA_BUENA_ID,                // geofenceId.
    115                 YERBA_BUENA_LATITUDE,
    116                 YERBA_BUENA_LONGITUDE,
    117                 YERBA_BUENA_RADIUS_METERS,
    118                 GEOFENCE_EXPIRATION_TIME,
    119                 Geofence.GEOFENCE_TRANSITION_ENTER | Geofence.GEOFENCE_TRANSITION_EXIT
    120         );
    121 
    122         // Store these flat versions in SharedPreferences and add them to the geofence list.
    123         mGeofenceStorage.setGeofence(ANDROID_BUILDING_ID, mAndroidBuildingGeofence);
    124         mGeofenceStorage.setGeofence(YERBA_BUENA_ID, mYerbaBuenaGeofence);
    125         mGeofenceList.add(mAndroidBuildingGeofence.toGeofence());
    126         mGeofenceList.add(mYerbaBuenaGeofence.toGeofence());
    127     }
    128 
    129 
    130     @Override
    131     public void onConnectionFailed(ConnectionResult connectionResult) {
    132         // If the error has a resolution, start a Google Play services activity to resolve it.
    133         if (connectionResult.hasResolution()) {
    134             try {
    135                 connectionResult.startResolutionForResult(this,
    136                         CONNECTION_FAILURE_RESOLUTION_REQUEST);
    137             } catch (IntentSender.SendIntentException e) {
    138                 Log.e(TAG, "Exception while resolving connection error.", e);
    139             }
    140         } else {
    141             int errorCode = connectionResult.getErrorCode();
    142             Log.e(TAG, "Connection to Google Play services failed with error code " + errorCode);
    143         }
    144     }
    145 
    146     /**
    147      * Once the connection is available, send a request to add the Geofences.
    148      */
    149     @Override
    150     public void onConnected(Bundle connectionHint) {
    151         // Get the PendingIntent for the geofence monitoring request.
    152         // Send a request to add the current geofences.
    153         mGeofenceRequestIntent = getGeofenceTransitionPendingIntent();
    154         LocationServices.GeofencingApi.addGeofences(mApiClient, mGeofenceList,
    155                 mGeofenceRequestIntent);
    156         Toast.makeText(this, getString(R.string.start_geofence_service), Toast.LENGTH_SHORT).show();
    157         finish();
    158     }
    159 
    160     @Override
    161     public void onConnectionSuspended(int i) {
    162         if (null != mGeofenceRequestIntent) {
    163             LocationServices.GeofencingApi.removeGeofences(mApiClient, mGeofenceRequestIntent);
    164         }
    165     }
    166 
    167 
    168     /**
    169      * Checks if Google Play services is available.
    170      * @return true if it is.
    171      */
    172     private boolean isGooglePlayServicesAvailable() {
    173         int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);
    174         if (ConnectionResult.SUCCESS == resultCode) {
    175             if (Log.isLoggable(TAG, Log.DEBUG)) {
    176                 Log.d(TAG, "Google Play services is available.");
    177             }
    178             return true;
    179         } else {
    180             Log.e(TAG, "Google Play services is unavailable.");
    181             return false;
    182         }
    183     }
    184 
    185     /**
    186      * Create a PendingIntent that triggers GeofenceTransitionIntentService when a geofence
    187      * transition occurs.
    188      */
    189     private PendingIntent getGeofenceTransitionPendingIntent() {
    190         Intent intent = new Intent(this, GeofenceTransitionsIntentService.class);
    191         return PendingIntent.getService(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
    192     }
    193 
    194 }
    195