Java tutorial
/** * Copyright 2017 Google Inc. All Rights Reserved. * * 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.unlp.tesis.steer; import android.app.ActivityManager; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; import android.app.Service; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; import android.content.res.Configuration; import android.graphics.Color; import android.location.Location; import android.os.Binder; import android.os.Bundle; import android.os.Handler; import android.os.HandlerThread; import android.os.IBinder; import android.os.Message; import android.os.Messenger; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.v4.app.NotificationCompat; import android.support.v4.content.LocalBroadcastManager; import android.support.v7.app.AlertDialog; import android.util.Log; import android.view.Gravity; import android.widget.TextView; import android.widget.Toast; import com.google.android.gms.common.ConnectionResult; import com.google.android.gms.common.api.GoogleApiClient; import com.google.android.gms.common.api.ResultCallback; import com.google.android.gms.common.api.Status; import com.google.android.gms.location.Geofence; import com.google.android.gms.location.GeofencingRequest; 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.maps.model.BitmapDescriptorFactory; import com.google.android.gms.maps.model.LatLng; import com.google.android.gms.maps.model.MarkerOptions; import com.google.firebase.database.DataSnapshot; import com.google.firebase.database.DatabaseError; import com.google.firebase.database.DatabaseReference; import com.google.firebase.database.FirebaseDatabase; import com.google.firebase.database.ValueEventListener; import com.unlp.tesis.steer.entities.GeofencePoint; import com.unlp.tesis.steer.entities.PaidParkingArea; import com.unlp.tesis.steer.entities.PointOfSale; import java.util.ArrayList; import java.util.Map; /** * A bound and started service that is promoted to a foreground service when location updates have * been requested and all clients unbind. * * For apps running in the background on "O" devices, location is computed only once every 10 * minutes and delivered batched every 30 minutes. This restriction applies even to apps * targeting "N" or lower which are run on "O" devices. * * This sample show how to use a long-running service for location updates. When an activity is * bound to this service, frequent location updates are permitted. When the activity is removed * from the foreground, the service promotes itself to a foreground service, and location updates * continue. When the activity comes back to the foreground, the foreground service stops, and the * notification assocaited with that service is removed. */ public class LocationService extends Service implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, LocationListener, ResultCallback<Status> { private static final String PACKAGE_NAME = "com.unlp.tesis.steer"; private static final String TAG = LocationService.class.getSimpleName(); private final IBinder mBinder = new LocalBinder(); /** * The desired interval for location updates. Inexact. Updates may be more or less frequent. */ private static final long UPDATE_INTERVAL_IN_MILLISECONDS = 4000; /** * The fastest rate for active location updates. Updates will never be more frequent * than this value. */ private static final long FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS = UPDATE_INTERVAL_IN_MILLISECONDS / 2; /** * Used to check whether the bound activity has really gone away and not unbound as part of an * orientation change. We create a foreground service notification only if the former takes * place. */ private boolean mChangingConfiguration = false; /** * The entry point to Google Play Services. */ public GoogleApiClient mGoogleApiClient; /** * Contains parameters used by {@link com.google.android.gms.location.FusedLocationProviderApi}. */ private LocationRequest mLocationRequest; private Handler mServiceHandler; /** * The current location. */ private Location mLocation = null; /** * The list of geofences used in this sample. */ protected ArrayList<Geofence> mGeofenceList; /** * Used when requesting to add or remove geofences. */ private PendingIntent mGeofencePendingIntent; private DatabaseReference mDatabase; public LocationService() { } @Override public void onCreate() { //GEOFENCES // Empty list for storing geofences. mGeofenceList = new ArrayList<Geofence>(); // Initially set the PendingIntent used in addGeofences() and removeGeofences() to null. mGeofencePendingIntent = null; // Get the geofences used. Geofence data is hard coded in this sample. //Get Firebase database instance mDatabase = FirebaseDatabase.getInstance().getReference(); populateGeofenceList(); if (mGoogleApiClient == null) { mGoogleApiClient = new GoogleApiClient.Builder(this).addConnectionCallbacks(this) .addOnConnectionFailedListener(this).addApi(LocationServices.API).build(); } mGoogleApiClient.connect(); createLocationRequest(); HandlerThread handlerThread = new HandlerThread(TAG); handlerThread.start(); mServiceHandler = new Handler(handlerThread.getLooper()); } @Override public int onStartCommand(Intent intent, int flags, int startId) { Log.i(TAG, "Service started"); return START_NOT_STICKY; } @Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); mChangingConfiguration = true; } @Override public IBinder onBind(Intent intent) { // Called when a client (MainActivity in case of this sample) comes to the foreground // and binds with this service. The service should cease to be a foreground service // when that happens. Log.i(TAG, "in onBind()"); return mBinder; } @Override public void onRebind(Intent intent) { // Called when a client (MainActivity in case of this sample) returns to the foreground // and binds once again with this service. The service should cease to be a foreground // service when that happens. Log.i(TAG, "in onRebind()"); super.onRebind(intent); } @Override public void onDestroy() { try { // Remove geofences. LocationServices.GeofencingApi.removeGeofences(mGoogleApiClient, // This is the same pending intent that was used in addGeofences(). getGeofencePendingIntent()).setResultCallback(this); // Result processed in onResult(). } catch (SecurityException securityException) { // Catch exception generated if the app does not use ACCESS_FINE_LOCATION permission. logSecurityException(securityException); } mServiceHandler.removeCallbacksAndMessages(null); if (mGoogleApiClient.isConnected()) mGoogleApiClient.disconnect(); super.onDestroy(); } /** * Makes a request for location updates. Note that in this sa * mple we merely log the * {@link SecurityException}. */ public void requestLocationUpdates() { Log.i(TAG, "Requesting location updates"); startService(new Intent(getApplicationContext(), LocationService.class)); try { LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, LocationService.this); } catch (SecurityException unlikely) { Log.e(TAG, "Lost location permission. Could not request updates. " + unlikely); } } @Override public void onConnected(@Nullable Bundle bundle) { Log.i(TAG, "GoogleApiClient connected"); try { // mLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient); requestLocationUpdates(); } catch (SecurityException unlikely) { Log.e(TAG, "Lost location permission." + unlikely); } } @Override public void onConnectionSuspended(int i) { // In this example, we merely log the suspension. Log.e(TAG, "GoogleApiClient connection suspended."); } @Override public void onConnectionFailed(@NonNull ConnectionResult connectionResult) { // In this example, we merely log the failure. Log.e(TAG, "GoogleApiClient connection failed."); } @Override public void onLocationChanged(Location location) { Log.i(TAG, "New location: " + location); // Notify anyone listening for broadcasts about the new location. Intent intent = new Intent(Constants.ACTION_BROADCAST); intent.putExtra(Constants.EXTRA_LOCATION, location); LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intent); mLocation = location; } /** * Sets the location request parameters. */ private void createLocationRequest() { mLocationRequest = new LocationRequest(); mLocationRequest.setInterval(UPDATE_INTERVAL_IN_MILLISECONDS); mLocationRequest.setFastestInterval(FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS); mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY); } /** * Class used for the client Binder. Since this service runs in the same process as its * clients, we don't need to deal with IPC. */ public class LocalBinder extends Binder { LocationService getService() { return LocationService.this; } } private void logSecurityException(SecurityException securityException) { Log.e(TAG, "Invalid location permission. " + "You need to use ACCESS_FINE_LOCATION with geofences", securityException); } private void InitGeofence() { //INIT GEOFENCES try { LocationServices.GeofencingApi.addGeofences(mGoogleApiClient, // The GeofenceRequest object. getGeofencingRequest(), // A pending intent that that is reused when calling removeGeofences(). This // pending intent is used to generate an intent when a matched geofence // transition is observed. getGeofencePendingIntent()).setResultCallback(this); // Result processed in onResult(). } catch (SecurityException securityException) { // Catch exception generated if the app does not use ACCESS_FINE_LOCATION permission. logSecurityException(securityException); } } /** * Builds and returns a GeofencingRequest. Specifies the list of geofences to be monitored. * Also specifies how the geofence notifications are initially triggered. */ private GeofencingRequest getGeofencingRequest() { GeofencingRequest.Builder builder = new GeofencingRequest.Builder(); // The INITIAL_TRIGGER_ENTER flag indicates that geofencing service should trigger a // GEOFENCE_TRANSITION_ENTER notification when the geofence is added and if the device // is already inside that geofence. builder.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER); // Add the geofences to be monitored by geofencing service. builder.addGeofences(mGeofenceList); // Return a GeofencingRequest. return builder.build(); } /** * Gets a PendingIntent to send with the request to add or remove Geofences. Location Services * issues the Intent inside this PendingIntent whenever a geofence transition occurs for the * current list of geofences. * * @return A PendingIntent for the IntentService that handles geofence transitions. */ private PendingIntent getGeofencePendingIntent() { // Reuse the PendingIntent if we already have it. if (mGeofencePendingIntent != null) { return mGeofencePendingIntent; } Intent intent = new Intent(getApplicationContext(), GeofenceTransitionsIntentService.class); // We use FLAG_UPDATE_CURRENT so that we get the same pending intent back when calling // addGeofences() and removeGeofences(). return PendingIntent.getService(getApplicationContext(), 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); } /** * Runs when the result of calling addGeofences() and removeGeofences() becomes available. * Either method can complete successfully or with an error. * * Since this activity implements the {@link ResultCallback} interface, we are required to * define this method. * * @param status The Status returned through a PendingIntent when addGeofences() or * removeGeofences() get called. */ public void onResult(Status status) { if (!status.isSuccess()) { // Get the status code for the error and log it using a user-friendly message. String errorMessage = GeofenceErrorMessages.getErrorString(this, status.getStatusCode()); Log.e(TAG, errorMessage); } } /** * This sample hard codes geofence data. A real app might dynamically create geofences based on * the user's location. */ public void populateGeofenceList() { mDatabase.child("paidParkingAreas").addValueEventListener(new ValueEventListener() { @Override public void onDataChange(DataSnapshot dataSnapshot) { for (DataSnapshot ds : dataSnapshot.getChildren()) { Log.e(TAG, "dataChange reading db"); // Get Post object and use the values to update the UI PaidParkingArea ppa = ds.getValue(PaidParkingArea.class); int i = 0; for (GeofencePoint gp : ppa.getGeofencePoints()) { mGeofenceList.add(new Geofence.Builder() // Set the request ID of the geofence. This is a string to identify this // geofence. .setRequestId(gp.getPaidParkingAreaId() + Constants.GEOFENCE_ID_DELIMITER + i) // Set the circular region of this geofence. .setCircularRegion(gp.getLatitude(), gp.getLongitude(), gp.getRadius()) // Set the expiration duration of the geofence. This geofence gets automatically // removed after this period of time. .setExpirationDuration(Constants.GEOFENCE_EXPIRATION_IN_MILLISECONDS) // Set the transition types of interest. Alerts are only generated for these // transition. We track entry and exit transitions in this sample. .setTransitionTypes( Geofence.GEOFENCE_TRANSITION_ENTER | Geofence.GEOFENCE_TRANSITION_EXIT) // Create the geofence. .build()); i++; } } InitGeofence(); } @Override public void onCancelled(DatabaseError databaseError) { Log.e(TAG, "Error reading db"); } }); } }