2015-07-25 3 views
0

Ive a ajouté tout le code nécessaire de la documentation google pour implémenter Geofencing dans android. Bien que je puisse plus ou moins comprendre ce qui se passe, j'essaie de rendre le processus aussi minimal que possible. Idéalement, l'utilisateur choisirait un emplacement et un geofence serait placé autour de lui. Une fois que l'utilisateur entre dans la zone, il doit déclencher une action. Pour l'instant, je suis juste en train d'essayer de coder en dur un endroit et de le faire fonctionner, puis de le prendre à partir de là. Cela étant dit, le contenu du bouton n'est probablement pas nécessaire ou la liste de tableaux d'événements spécifiés.Pourquoi Google Geofencing ne fonctionne-t-il pas dans mon application Android?

Ma question est de savoir quel est le code minimum nécessaire pour implémenter ce processus et quelle est la meilleure façon de s'y prendre? Ceci est ma première application Android alors allez-y doucement sur le chahut.

public class MapsActivity extends FragmentActivity implements 
    GoogleApiClient.ConnectionCallbacks, 
    GoogleApiClient.OnConnectionFailedListener, 
    LocationListener { 


@Override 
protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 


     setContentView(R.layout.activity_maps); 

     // Kick off the request to build GoogleApiClient. 
     buildGoogleApiClient(); 

     mGeofencePendingIntent = null; 
     // Get the value of mGeofencesAdded from SharedPreferences. Set to false as a default. 
     mGeofencesAdded = mSharedPreferences.getBoolean(Constants.GEOFENCES_ADDED_KEY, false); 

     // Get the geofences used. Geofence data is hard coded in this sample. 
     populateGeofenceList(); 
     getGeofencePendingIntent(); 
     getGeofencingRequest(); 

     addGeofencesButtonHandler(this); 

     //Get the UI widgets. 
     mAddGeofencesButton = (Button) findViewById(R.id.add_geofences_button); 
     mRemoveGeofencesButton = (Button) findViewById(R.id.remove_geofences_button); 

     mSharedPreferences = getSharedPreferences(Constants.SHARED_PREFERENCES_NAME, 
     MODE_PRIVATE); 
    } 

} 

@Override 
public void onConnected(Bundle bundle) { 
    mLocationRequest = LocationRequest.create(); 
    mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY); 
    mLocationRequest.setInterval(1000); // Update location every second 

    LocationServices.FusedLocationApi.requestLocationUpdates(
      mGoogleApiClient, mLocationRequest, this); 
} 


@Override 
public void onLocationChanged(Location location) { 

    double lat = location.getLatitude(); 
    double lng = location.getLongitude(); 

     myLat = lat; 
     myLng = lng; 
     mapCenter = new LatLng(myLat, myLng); 
     mMap.moveCamera(CameraUpdateFactory.newLatLng(mapCenter)); 
} 

/** 
* Builds a GoogleApiClient. Uses the {@code #addApi} method to request the LocationServices API. 
*/ 
protected synchronized void buildGoogleApiClient() { 
    mGoogleApiClient = new GoogleApiClient.Builder(this) 
      .addConnectionCallbacks(this) 
      .addOnConnectionFailedListener(this) 
      .addApi(LocationServices.API) 
      .build(); 
} 

private void setUpMap() { 

    // Enable MyLocation Layer of Google Map 
    mMap.setMyLocationEnabled(true); 

    // Get LocationManager object from System Service LOCATION_SERVICE 
    locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE); 

    // set map type 
    mMap.setMapType(GoogleMap.MAP_TYPE_NORMAL); 

    // Get the name of the best provider 
    String networkProvider = locationManager.NETWORK_PROVIDER; 
    String gpsProvider = locationManager.GPS_PROVIDER; 

    // Get Best Current Location 
    myLocation = locationManager.getLastKnownLocation(networkProvider); 

     // Get latitude of the current location 
     double latitude = myLocation.getLatitude(); 

     // Get longitude of the current location 
     double longitude = myLocation.getLongitude(); 

     // Create a LatLng object for the current location 
     LatLng latLng = new LatLng(latitude, longitude); 

     // Show the current location in Google Map 
     mMap.moveCamera(CameraUpdateFactory.newLatLng(latLng)); 

     // Zoom in the Google Map 
     mMap.animateCamera(CameraUpdateFactory.zoomTo(14)); 

     //Add Marker For event 
     Intent myIntent = getIntent(); 
     String desc = myIntent.getStringExtra("desc"); 
     String addr = myIntent.getStringExtra("addr"); 
     venueLat = myIntent.getDoubleExtra("lat", 0.0); 
     venueLng = myIntent.getDoubleExtra("lon", 0.0); 

     mMap.addMarker(new MarkerOptions().position(new LatLng(venueLat, venueLng)).title(desc).snippet(addr)); 
    } 

} 

/* 
* 
* 
* 
* 
* Geofence Stuff 
* 
* 
* 
* 
*/ 


private PendingIntent getGeofencePendingIntent() { 
    // Reuse the PendingIntent if we already have it. 
    if (mGeofencePendingIntent != null) { 
     return mGeofencePendingIntent; 
    } 
    Intent intent = new Intent(this, GeofenceTransitionsIntentService.class); 
    // We use FLAG_UPDATE_CURRENT so that we get the same pending intent back when 
    // calling addGeofences() and removeGeofences(). 
    return PendingIntent.getService(this, 0, intent, PendingIntent. 
      FLAG_UPDATE_CURRENT); 
} 

private GeofencingRequest getGeofencingRequest() { 
    GeofencingRequest.Builder builder = new GeofencingRequest.Builder(); 
    builder.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER); 
    builder.addGeofences(mGeofenceList); 
    return builder.build(); 
} 


/** 
* This sample hard codes geofence data. A real app might dynamically create geofences based on 
* the users location. 
*/ 
public void populateGeofenceList() { 
    for (Map.Entry<String, LatLng> entry : Constants.BAY_AREA_LANDMARKS.entrySet()) { 

     mGeofenceList.add(new Geofence.Builder() 
       // Set the request ID of the geofence. This is a string to identify this 
       // geofence. 
       .setRequestId(entry.getKey()) 

         // Set the circular region of this geofence. 
       .setCircularRegion(
         entry.getValue().latitude, 
         entry.getValue().longitude, 
         Constants.GEOFENCE_RADIUS_IN_METERS 
       ) 

         // 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()); 
    } 
} 




public void addGeofencesButtonHandler(View view) { 
    if (!mGoogleApiClient.isConnected()) { 
     Toast.makeText(this, getString(R.string.not_connected), Toast.LENGTH_SHORT).show(); 
     return; 
    } 

    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((ResultCallback<Status>) this); // Result processed in onResult(). 
    } catch (SecurityException securityException) { 
     // Catch exception generated if the app does not use ACCESS_FINE_LOCATION permission. 
     // logSecurityException(securityException); 
    } 
} 



/** 
* 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()) { 
     // Update state and save in shared preferences. 
     mGeofencesAdded = !mGeofencesAdded; 
     SharedPreferences.Editor editor = mSharedPreferences.edit(); 
     editor.putBoolean(Constants.GEOFENCES_ADDED_KEY, mGeofencesAdded); 
     editor.commit(); 

     // Update the UI. Adding geofences enables the Remove Geofences button, and removing 
     // geofences enables the Add Geofences button. 
     setButtonsEnabledState(); 

     Toast.makeText(
       this, 
       getString(mGeofencesAdded ? R.string.geofences_added : 
         R.string.geofences_removed), 
       Toast.LENGTH_SHORT 
     ).show(); 
    } else { 
     // 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); 
    } 
} 


/** 
* Ensures that only one button is enabled at any time. The Add Geofences button is enabled 
* if the user hasnt yet added geofences. The Remove Geofences button is enabled if the 
* user has added geofences. 
*/ 
private void setButtonsEnabledState() { 
    if (mGeofencesAdded) { 
     mAddGeofencesButton.setEnabled(false); 
     mRemoveGeofencesButton.setEnabled(true); 
    } else { 
     mAddGeofencesButton.setEnabled(true); 
     mRemoveGeofencesButton.setEnabled(false); 
    } 
} 


} 




/* 
* --------------------------------------------------------------------------------------- 
*/ 



public class GeofenceTransitionsIntentService extends IntentService { 
protected static final String TAG = "geofence-transitions-service"; 


/** 
* This constructor is required, and calls the super IntentService(String) 
* constructor with the name for a worker thread. 
*/ 
public GeofenceTransitionsIntentService() { 
    // Use the TAG to name the worker thread. 
    super(TAG); 
} 

@Override 
public void onCreate() { 
    super.onCreate(); 
} 

/** 
* Handles incoming intents. 
* @param intent sent by Location Services. This Intent is provided to Location 
*    Services (inside a PendingIntent) when addGeofences() is called. 
*/ 
@Override 
protected void onHandleIntent(Intent intent) { 
    GeofencingEvent geofencingEvent = GeofencingEvent.fromIntent(intent); 
    if (geofencingEvent.hasError()) { 
     String errorMessage = GeofenceErrorMessages.getErrorString(this, 
       geofencingEvent.getErrorCode()); 
     Log.e(TAG, errorMessage); 
     return; 
    } 

    // Get the transition type. 
    int geofenceTransition = geofencingEvent.getGeofenceTransition(); 

    // Test that the reported transition was of interest. 
    if (geofenceTransition == Geofence.GEOFENCE_TRANSITION_ENTER || 
      geofenceTransition == Geofence.GEOFENCE_TRANSITION_EXIT) { 

     // Get the geofences that were triggered. A single event can trigger multiple geofences. 
     List<Geofence> triggeringGeofences = geofencingEvent.getTriggeringGeofences(); 

     // Get the transition details as a String. 
     String geofenceTransitionDetails = getGeofenceTransitionDetails(
       this, 
       geofenceTransition, 
       triggeringGeofences 
     ); 

     // Send notification and log the transition details. 
     sendNotification(geofenceTransitionDetails); 
     // Toast.makeText(getApplicationContext(), geofenceTransitionDetails, Toast.LENGTH_SHORT).show(); 
     Log.i(TAG, geofenceTransitionDetails); 
    } else { 
     // Log the error. 
     Log.e(TAG, getString(R.string.geofence_transition_invalid_type, geofenceTransition)); 
    } 
} 

/** 
* Gets transition details and returns them as a formatted string. 
* 
* @param context    The app context. 
* @param geofenceTransition The ID of the geofence transition. 
* @param triggeringGeofences The geofence(s) triggered. 
* @return      The transition details formatted as String. 
*/ 
private String getGeofenceTransitionDetails(
     Context context, 
     int geofenceTransition, 
     List<Geofence> triggeringGeofences) { 

    String geofenceTransitionString = getTransitionString(geofenceTransition); 

    // Get the Ids of each geofence that was triggered. 
    ArrayList triggeringGeofencesIdsList = new ArrayList(); 
    for (Geofence geofence : triggeringGeofences) { 
     triggeringGeofencesIdsList.add(geofence.getRequestId()); 
    } 
    String triggeringGeofencesIdsString = TextUtils.join(", ", triggeringGeofencesIdsList); 

    return geofenceTransitionString + ": " + triggeringGeofencesIdsString; 
} 

/** 
* Posts a notification in the notification bar when a transition is detected. 
* If the user clicks the notification, control goes to the MainActivity. 
*/ 
private void sendNotification(String notificationDetails) { 
    // Create an explicit content Intent that starts the main Activity. 
    Intent notificationIntent = new Intent(getApplicationContext(), MapsActivity.class); 

    // Construct a task stack. 
    TaskStackBuilder stackBuilder = TaskStackBuilder.create(this); 

    // Add the main Activity to the task stack as the parent. 
    stackBuilder.addParentStack(MapsActivity.class); 

    // Push the content Intent onto the stack. 
    stackBuilder.addNextIntent(notificationIntent); 

    // Get a PendingIntent containing the entire back stack. 
    PendingIntent notificationPendingIntent = 
      stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT); 

    // Get a notification builder thats compatible with platform versions >= 4 
    NotificationCompat.Builder builder = new NotificationCompat.Builder(this); 

    // Define the notification settings. 
    builder.setSmallIcon(R.drawable.ic_launcher) 
      // In a real app, you may want to use a library like Volley 
      // to decode the Bitmap. 
      .setLargeIcon(BitmapFactory.decodeResource(getResources(), 
        R.drawable.ic_launcher)) 
      .setColor(Color.RED) 
      .setContentTitle(notificationDetails) 
      .setContentText(getString(R.string.geofence_transition_notification_text)) 
      .setContentIntent(notificationPendingIntent); 

    // Dismiss notification once the user touches it. 
    builder.setAutoCancel(true); 

    // Get an instance of the Notification manager 
    NotificationManager mNotificationManager = 
      (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); 

    // Issue the notification 
    mNotificationManager.notify(0, builder.build()); 
} 

/** 
* Maps geofence transition types to their human-readable equivalents. 
* 
* @param transitionType A transition type constant defined in Geofence 
* @return     A String indicating the type of transition 
*/ 
private String getTransitionString(int transitionType) { 
    switch (transitionType) { 
     case Geofence.GEOFENCE_TRANSITION_ENTER: 
      return getString(R.string.geofence_transition_entered); 
     case Geofence.GEOFENCE_TRANSITION_EXIT: 
      return getString(R.string.geofence_transition_exited); 
     default: 
      return getString(R.string.unknown_geofence_transition); 
    } 
} 
} 

/* 
* -------------------------------------------------------------------------- 
*/ 


public class Constants { 
private Constants() { 
} 

public static final String PACKAGE_NAME = "com.google.android.gms.location.Geofence"; 

public static final String SHARED_PREFERENCES_NAME = PACKAGE_NAME + ".SHARED_PREFERENCES_NAME"; 

public static final String GEOFENCES_ADDED_KEY = PACKAGE_NAME + ".GEOFENCES_ADDED_KEY"; 

/** 
* Used to set an expiration time for a geofence. After this amount of time Location Services 
* stops tracking the geofence. 
*/ 
public static final long GEOFENCE_EXPIRATION_IN_HOURS = 12; 

/** 
* For this sample, geofences expire after twelve hours. 
*/ 
public static final long GEOFENCE_EXPIRATION_IN_MILLISECONDS = 
     GEOFENCE_EXPIRATION_IN_HOURS * 60 * 60 * 1000; 
public static final float GEOFENCE_RADIUS_IN_METERS = 1609; // 1 mile, 1.6 km 

/** 
* Map for storing information about airports in the San Francisco bay area. 
*/ 
public static final HashMap<String, LatLng> BAY_AREA_LANDMARKS = new HashMap<String, LatLng>(); 
static { 

    BAY_AREA_LANDMARKS.put("Home", new LatLng(29.382798, -98.529470)); 


    BAY_AREA_LANDMARKS.put("Other Home", new LatLng(29.472491,-98.571244)); 
} 
} 

Répondre

1

Voici quelques suggestions concernant votre code:

  • Essayez de le rendre plus modulaire. Séparer le code dans différents fichiers en fonction de la fonctionnalité que vous attendez qu'ils supportent (par exemple, le code des cartes peut être séparé de l'emplacement, etc.).
  • Assurez-vous que votre application dispose de la dernière version des services Google Play et qu'elle utilise la fonction FusedLocationApi.
  • Assurez-vous que le rayon de geofence est altelast 100 mètres. Sinon, le code de sortie d'entrée ne sera pas déclenché.
  • Ajouter les autorisations nécessaires dans les fichiers manifestes tels que ACCESS_FINE_LOCATION, BroadcastReceiver (si vous utilisez), etc.

S'il vous plaît se référer à la mise en œuvre du code de la tutorial suivante.

+0

le lien ci-dessus ne fonctionne plus –