Ive added all the necessary code from the google documentation for implementing Geofencing in android. Although I can more or less understand what is going on, im trying to make the process as minimal as possible. Ideally, the user would pick a location and a geofence gets set around it. Once user enters the area, it should trigger an action. For now I am just trying to hard-code a location and get that working then take it from there. With that being said the button stuff is probably not necessary or the array-list of specified events.
My question is what is the bare minimum code I need to implement this process and what is the best way to go about it? This is my first android app so go easy on the heckling.
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));
}
}
Here are few suggestions regarding your code:
Try to make it more modular. Separate out the code in different files according to the functionality you are expecting them to support (eg, maps code can be separated from location etc).
Make sure your app has the latest version of Google Play Services and making use of the FusedLocationApi.
Make sure the geofence radius is altelast 100 meters. Else the enter exit code wont be triggered.
Add the necessary permissions in the manifest files such as ACCESS_FINE_LOCATION, BroadCastreceiver (if you are using) etc.
Please refer to the following tutorial for code implementation.
Related
This question already has answers here:
Today is nth day of year [duplicate]
(6 answers)
Converting a Date object to a calendar object [duplicate]
(3 answers)
Closed 1 year ago.
I have an app that defines a Geofence location in an Activity called SearchSchool. I then implemented a BroadCastReceiver extension in another class to listen when user enters the geolocation and when he leaves it. I seem to have done everything correctly except the part where am supposed to send a notification to user from the BroadcastReceiverClass to the SearchSchool Activity which is an extension of AppCompatActivity class.
Here is the code in the SearchSchool activity that defines the Geofence builder...
public class Search_School extends AppCompatActivity {
PendingIntent geofencePendingIntent;
private GeofencingClient geofencingClient;
List<Geofence> geofences = new ArrayList<>();
//replace with real latitude and longitude of your geofence
//define the longitude and latitude of the geofence and radius
private double lat = 37.8136;
double lon = 74.0060;
private float radius = 100;
private long EXPIRATION_TIME = 10000;
#Override
protected void OnCreate(Bundle savedInstanceState){
geofencingClient = LocationServices.getGeofencingClient(this);
geofences.add(new Geofence.Builder()
.setRequestId("MyGeofence")
.setCircularRegion(lat, lon, radius)
.setExpirationDuration(EXPIRATION_TIME).
setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER | Geofence.GEOFENCE_TRANSITION_EXIT)
.build());
//add a geofence to the client
geofencingClient.addGeofences(getGeofencingRequest(), getGeofencePendingIntent())
.addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void aVoid) {
Toast.makeText(getActivity(), "Geofence added with success",Toast.LENGTH_LONG).show();
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Toast.makeText(getActivity(),"Geofence addtion failed",Toast.LENGTH_LONG).show();
}
});
}
//create a geofence request
private GeofencingRequest getGeofencingRequest() {
GeofencingRequest.Builder builder =new GeofencingRequest.Builder();
builder.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER);
builder.addGeofences(geofences);
return builder.build();
}
//Create a geofence pendingRequest
private PendingIntent getGeofencePendingIntent() {
// Reuse the PendingIntent if we already have it.
if (geofencePendingIntent != null) {
return geofencePendingIntent;
}
Intent intent = new Intent(this, GeofenceBroadcastReceiver.class);
// We use FLAG_UPDATE_CURRENT so that we get the same pending intent back when
// calling addGeofences() and removeGeofences().
geofencePendingIntent = PendingIntent.getBroadcast(this, 0, intent, PendingIntent.
FLAG_UPDATE_CURRENT);
return geofencePendingIntent;
}
}
Here is the BroadCastReeceiver class for detecting when user has entered the geofence and should send a notification to SearchSchoolactivity when it occurs
package com.example.fastuniforms;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import android.widget.Toast;
import com.google.android.gms.location.Geofence;
import com.google.android.gms.location.GeofenceStatusCodes;
import com.google.android.gms.location.GeofencingEvent;
import java.util.List;
import static android.content.ContentValues.TAG;
public class GeofenceBroadcastReceiver extends BroadcastReceiver {
// ...
public void onReceive(Context context, Intent intent) {
GeofencingEvent geofencingEvent = GeofencingEvent.fromIntent(intent);
if (geofencingEvent.hasError()) {
String errorMessage = GeofenceStatusCodes
.getStatusCodeString(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
);
// I havea problem creating a notification method in a non Activity class
sendNotification(geofenceTransitionDetails);
Log.i(TAG, geofenceTransitionDetails);
} else {
// Log the error.
Log.e(TAG,"An error occurred, try again in a little bit");
}
}
//i have a major problem here getting the details and sending them
private String getGeofenceTransitionDetails(GeofenceBroadcastReceiver geofenceBroadcastReceiver, int geofenceTransition, List<Geofence> triggeringGeofences) {
}
}
I have a problem with the two areas highlighted in the second class, please help me make the getGeofenceTransitionDetailsand the ``sendNotification` methods work Thank You
I've been using the Google Location Services API with Geofences. I can successfully catch Geofence transitions and I receive notifications when I enter and exit Geofences. However, I do not know how to make a Geofence transition make GUI and Data changes to the app.
For an example, if the app is open, I want a small toast to appear. I also need my app to generate a new geofence and discard the old one (but so far I'm only using a set of hardcoded geofences).
But so far, I do not understand how I can interact with my app from the GeofenceTransitionsEventService.java (which is where I "catch" the intents and create the notifications).
Below is my code (now edited, but still not working):
GPS Activity
public class GPSActivity extends AppCompatActivity implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, LocationListener, ResultCallback<Status> {
private GoogleApiClient mGoogleApiClient;
private LocationRequest mLocationRequest;
private String mLastUpdateTime;
private TextView mLatitudeTextView;
private TextView mLongitudeTextView;
private final int MY_PERMISSION_ACCESS_FINE_LOCATION = 1;
private boolean locationPermissionGoodToGo = false;
public double latitude, longitude = 50;
protected static final String TAG = "MainActivity";
/**
* The list of geofences used in this sample.
*/
protected ArrayList<Geofence> mGeofenceList;
/**
* Used to keep track of whether geofences were added.
*/
private boolean mGeofencesAdded;
/**
* Used when requesting to add or remove geofences.
*/
private PendingIntent mGeofencePendingIntent;
/**
* Used to persist application state about whether geofences were added.
*/
private SharedPreferences mSharedPreferences;
// Buttons for kicking off the process of adding or removing geofences.
private Button mAddGeofencesButton;
private Button mRemoveGeofencesButton;
protected ResultReceiver mResultReceiver;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_gps);
mLatitudeTextView = (TextView) findViewById((R.id.latitude_textview));
mLongitudeTextView = (TextView) findViewById((R.id.longitude_textview));
// Get the UI widgets.
mAddGeofencesButton = (Button) findViewById(R.id.add_geofences_button);
mRemoveGeofencesButton = (Button) findViewById(R.id.remove_geofences_button);
// Empty list for storing geofences.
mGeofenceList = new ArrayList<Geofence>();
// Initially set the PendingIntent used in addGeofences() and removeGeofences() to null.
mGeofencePendingIntent = null;
// Retrieve an instance of the SharedPreferences object.
mSharedPreferences = getSharedPreferences(Constants.SHARED_PREFERENCES_NAME,
MODE_PRIVATE);
// Get the value of mGeofencesAdded from SharedPreferences. Set to false as a default.
mGeofencesAdded = mSharedPreferences.getBoolean(Constants.GEOFENCES_ADDED_KEY, false);
setButtonsEnabledState();
// Get the geofences used. Geofence data is hard coded in this sample.
populateGeofenceList();
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
initReceiver();
}
public void initReceiver(){
mResultReceiver = new AddressResultReceiver(new Handler()) {
#Override
protected void onReceiveResult(int resultCode, Bundle resultData) {
// Check result code and/or resultData and take necessary action
if(resultCode == 0){
makeToast(resultData.getString("FROM_GEOFENCE_KEY"));
mRemoveGeofencesButton.setText("Remove TESTT");
}
}
};
// if(mResultReceiver != null){
// mAddGeofencesButton.setText("Add Geofences NOT NULL TEST");
//}
Intent intent = new Intent(this, GeofenceTransitionsIntentService.class);
intent.putExtra(Constants.RECEIVER, mResultReceiver);
}
public void makeToast(String string){
Toast.makeText(this, string, Toast.LENGTH_LONG).show();
}
#Override
protected void onStart() {
super.onStart();
mGoogleApiClient.connect();
}
#Override
protected void onStop() {
super.onStop();
if (mGoogleApiClient.isConnected()) {
mGoogleApiClient.disconnect();
}
}
#Override
public void onConnected(Bundle bundle) {
mLocationRequest = LocationRequest.create();
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
mLocationRequest.setInterval(5000);
mLocationRequest.setFastestInterval(3000);
if ( ContextCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED ) {
ActivityCompat.requestPermissions(this, new String[]{android.Manifest.permission.ACCESS_FINE_LOCATION}, MY_PERMISSION_ACCESS_FINE_LOCATION);
}
// setCoordinates();
else{
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);
}
}
#Override
public void onConnectionSuspended(int i) {
Log.i(TAG, "Connection Suspended");
mGoogleApiClient.connect();
}
#Override
public void onLocationChanged(Location location) {
mLastUpdateTime = DateFormat.getTimeInstance().format(new Date());
mLatitudeTextView.setText(String.valueOf(location.getLatitude()));
mLongitudeTextView.setText(String.valueOf(location.getLongitude()));
latitude = location.getLatitude();
longitude = location.getLongitude();
// Toast.makeText(this, "Updated: " + mLastUpdateTime, Toast.LENGTH_SHORT).show();
}
#Override
public void onConnectionFailed(ConnectionResult connectionResult) {
Log.i(TAG, "Connection failed. Error: " + connectionResult.getErrorCode());
}
#Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
switch (requestCode) {
case MY_PERMISSION_ACCESS_FINE_LOCATION: {
// If request is cancelled, the result arrays are empty.
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// permission was granted, yay! Do the
// contacts-related task you need to do.
locationPermissionGoodToGo = true;
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);
//setCoordinates();
} else {
// permission denied, boo! Disable the
// functionality that depends on this permission.
locationPermissionGoodToGo = false;
}
return;
}
// other 'case' lines to check for other
// permissions this app might request
}
}
public void startGame(){
//mGeofenceList.add(new Geofence.Builder()
Geofence fence = new Geofence.Builder()
// Set the request ID of the geofence. This is a string to identify this geofence.
.setRequestId("hej")
.setCircularRegion(latitude, longitude, 150) //radius in meters
.setExpirationDuration(Geofence.NEVER_EXPIRE)
.setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER | Geofence.GEOFENCE_TRANSITION_EXIT)
.build();//;
}
/**
* 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();
}
/**
* Adds geofences, which sets alerts to be notified when the device enters or exits one of the
* specified geofences. Handles the success or failure results returned by addGeofences().
*/
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(this); // Result processed in onResult().
} catch (SecurityException securityException) {
// Catch exception generated if the app does not use ACCESS_FINE_LOCATION permission.
logSecurityException(securityException);
}
}
/**
* Removes geofences, which stops further notifications when the device enters or exits
* previously registered geofences.
*/
public void removeGeofencesButtonHandler(View view) {
if (!mGoogleApiClient.isConnected()) {
Toast.makeText(this, getString(R.string.not_connected), Toast.LENGTH_SHORT).show();
return;
}
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);
}
}
private void logSecurityException(SecurityException securityException) {
Log.e(TAG, "Invalid location permission. " +
"You need to use ACCESS_FINE_LOCATION with geofences", 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.apply();
// 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);
}
}
/**
* 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(this, GeofenceTransitionsIntentService.class);
//DESTROYS EVERYTHING---> intent.putExtra("RECEIVER_KEY", mResultReceiver);
// 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);
}
/**
* This sample hard codes geofence data. A real app might dynamically create geofences based on
* the user's 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());
}
}
/**
* Ensures that only one button is enabled at any time. The Add Geofences button is enabled
* if the user hasn't 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);
}
}
}
GeofenceTransisitionsIntentService
public class GeofenceTransitionsIntentService extends IntentService {
protected static final String TAG = "GeofenceTransitionsIS";
private ResultReceiver mResultReceiver;
/**
* 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();
//Intent i = getIntent();
}
/**
* 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) {
mResultReceiver = intent.getParcelableExtra(Constants.RECEIVER);
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);
sendToActivity("Sending to activity test");
//Toast.makeText(this, geofenceTransitionDetails, Toast.LENGTH_SHORT).show();
Log.i(TAG, geofenceTransitionDetails);
} else {
// Log the error.
Log.e(TAG, "R.string.geofence_transition_invalid_type");
}
}
/**
* 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(), GPSActivity.class);
// Construct a task stack.
TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
// Add the main Activity to the task stack as the parent.
stackBuilder.addParentStack(GPSActivity.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 that's 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 void sendToActivity(String string){
Bundle b=new Bundle();
b.putString("FROM_GEOFENCE_KEY", string);
mResultReceiver.send(0, b);
}
}
Here is my current error message which causes the app to crash
04-11 17:21:21.952 9528-9528/blueinteraction.mamn01blueinteraction W/System: ClassLoader referenced unknown path: /data/app/blueinteraction.mamn01blueinteraction-1/lib/arm
04-11 17:21:21.974 9528-9528/blueinteraction.mamn01blueinteraction I/GMPM: App measurement is starting up, version: 8487
04-11 17:21:21.974 9528-9528/blueinteraction.mamn01blueinteraction I/GMPM: To enable debug logging run: adb shell setprop log.tag.GMPM VERBOSE
04-11 17:21:21.983 9528-9528/blueinteraction.mamn01blueinteraction E/GMPM: GoogleService failed to initialize, status: 10, Missing an expected resource: 'R.string.google_app_id' for initializing Google services. Possible causes are missing google-services.json or com.google.gms.google-services gradle plugin.
04-11 17:21:21.984 9528-9528/blueinteraction.mamn01blueinteraction E/GMPM: Scheduler not set. Not logging error/warn.
04-11 17:21:22.008 9528-9528/blueinteraction.mamn01blueinteraction I/InstantRun: Starting server socket listening for package blueinteraction.mamn01blueinteraction on android.net.LocalSocketAddress#e9aec24
04-11 17:21:22.010 9528-9528/blueinteraction.mamn01blueinteraction I/InstantRun: Started server for package blueinteraction.mamn01blueinteraction
04-11 17:21:22.012 9528-9567/blueinteraction.mamn01blueinteraction E/GMPM: Uploading is not possible. App measurement disabled
04-11 17:21:22.138 9528-9572/blueinteraction.mamn01blueinteraction D/OpenGLRenderer: Use EGL_SWAP_BEHAVIOR_PRESERVED: true
04-11 17:21:22.196 9528-9572/blueinteraction.mamn01blueinteraction I/Adreno-EGL: <qeglDrvAPI_eglInitialize:379>: QUALCOMM Build: 10/21/15, 369a2ea, I96aee987eb
04-11 17:21:22.199 9528-9572/blueinteraction.mamn01blueinteraction I/OpenGLRenderer: Initialized EGL, version 1.4
04-11 17:21:23.868 9528-9572/blueinteraction.mamn01blueinteraction D/OpenGLRenderer: endAllStagingAnimators on 0xb40e3280 (RippleDrawable) with handle 0x9f7bf6f0
04-11 17:21:29.767 9528-9572/blueinteraction.mamn01blueinteraction V/RenderScript: 0xaeca2000 Launching thread(s), CPUs 4
04-11 17:21:29.793 9528-9769/blueinteraction.mamn01blueinteraction E/AndroidRuntime: FATAL EXCEPTION: IntentService[GeofenceTransitionsIS]
Process: blueinteraction.mamn01blueinteraction, PID: 9528
java.lang.NullPointerException: Attempt to invoke virtual method 'void android.os.ResultReceiver.send(int, android.os.Bundle)' on a null object reference
at blueinteraction.mamn01blueinteraction.GeofenceTransitionsIntentService.sendToActivity(GeofenceTransitionsIntentService.java:187)
at blueinteraction.mamn01blueinteraction.GeofenceTransitionsIntentService.onHandleIntent(GeofenceTransitionsIntentService.java:87)
at android.app.IntentService$ServiceHandler.handleMessage(IntentService.java:66)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:148)
at android.os.HandlerThread.run(HandlerThread.java:61)
04-11 17:21:29.898 9528-9572/blueinteraction.mamn01blueinteraction D/OpenGLRenderer: endAllStagingAnimators on 0x9eee6280 (RippleDrawable) with handle 0x9f7bf670
I think these are the only classes I need to show you here for you to be able to help. Otherwise tell me what else to include.
You can use ResultReceiver to send data back to Activity or Fragment
https://developer.android.com/reference/android/os/ResultReceiver.html
its send method would allow to add resultCode and Bundle to send data back to class which implemented the receiver.
From your Activity or Fragment, you will pass an instance of receiver to the IntentService. Such as,
Intent intent = new Intent(context, GeofenceTransitionsIntentService.class);
intent.putExtra(Constants.RECEIVER, receiver);
activity.startService(intent);
Now in your IntentService class, you would get the receiver via bungle arguments and keep an instance in the class.
In your IntentService's onHandleIntent method, probably any where else you want to trigger the event, you will use the receiver to send the data back to the calling class. Something like this,
protected void onHandleIntent(Intent intent) {
ResultReceiver resultReceiver = intent.getParcelableExtra(Constants.RECEIVER);
}
ResultReceiver is Generic interface for receiving a callback result from someone. Use this by creating a subclass and implement onReceiveResult(int, Bundle), which you can then pass to others and send through IPC, and receive results they supply with send(int, Bundle).
So extend that class and create a new class in your app like this,
public abstract class AddressResultReceiver extends ResultReceiver {
public AddressResultReceiver(Handler handler) {
super(handler);
}
}
Then AddressResultReceiver might look something like this in your Activity,
protected AddressResultReceiver mResultReceiver = new AddressResultReceiver(new Handler()) {
#Override
protected void onReceiveResult(int resultCode, Bundle resultData) {
// Check result code and/or resultData and take necessary action
}
};
I hope this helps.
My app uses geofences to notify the user when the enter a location, a notification gets displayed when the user enters the location.
what im trying to to is get the triggering geofences convert them to a string, then send them to another activity so that they can be displayed in a list view.
Ive watched tutorials online on how to makes list views and how to send data using intents but what im trying to do just doesn't seem to work.
EDIT
I'm starting the list view PageActivity using a intent with startActivity from another class the MainActivity.
Goals
If the user clicks on the notification from anywhere especially from outside the application it will open the app with the list view being filled with the geofence details. If the user opens the app just opens the app the from the launcher, then the same to happen. The list to be filled with any geofences that were triggered.
GeofenceTransitionsIntentService Class:
public class GeofenceTransitionsIntentService extends IntentService {
protected static final String TAG = "GeofenceTransitionsIS";
/**
* 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 Transistion Type
int geofenceTransition = geofencingEvent.getGeofenceTransition();
// Test that the reported transisition 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 transistion details as a String.
String geofenceTransitionDetails = getGeofenceTransitionDetails(
this,
geofenceTransition,
triggeringGeofences
);
headsUpSmsNotifaction(geofenceTransitionDetails);
Intent i = new Intent(this, listPageActivty.class);
i.putExtra("intentKey",geofenceTransitionDetails);
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 headsUpSmsNotifaction(String notificationDetails){
// Create an explicit content Intent that starts the main Activity.
Intent notificationIntent = new Intent(this, sendSmsReceiver.class);
PendingIntent notificationPendingIntent = PendingIntent.getBroadcast(this,44,notificationIntent,0);
Calendar calendar = Calendar.getInstance();
SimpleDateFormat mdfromat = new SimpleDateFormat("hh:ss | dd/ MM / yyyy");
String strDate = mdfromat.format(calendar.getTime());
// Get a notification builder that's compatible with platform versions >= 4
NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
// Define the notification settings.
builder.setSmallIcon(R.mipmap.ic_launcher)
// In a real app, you may want to use a library like Volley
// to decode the Bitmap.
.setLargeIcon(BitmapFactory.decodeResource(getResources(),
R.mipmap.ic_launcher))
.setColor(Color.RED)
.setPriority(NotificationCompat.PRIORITY_MAX)
.setVibrate(new long[]{10,10,10})
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
.setContentTitle(notificationDetails)
.setContentText(strDate)
.addAction(R.mipmap.ic_launcher,"send",notificationPendingIntent)
.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);
}
}
}
listPageActivty Class:
public class listPageActivty extends AppCompatActivity {
ListView listView;
String[] ListElements = new String[]{"Android","PHP"};
String item = "one";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_list_page_activty);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
listView = (ListView) findViewById(R.id.listView2);
Button addBtn = (Button) findViewById(R.id.addBtn);
final List<String> ListElementsArrayList = new ArrayList<String>(Arrays.asList(ListElements));
final ArrayAdapter<String> adapter = new ArrayAdapter<String>(listPageActivty.this,android.R.layout.simple_list_item_1,ListElementsArrayList);
listView.setAdapter(adapter);
Bundle bundleData = getIntent().getExtras();
if (bundleData == null){
return;
}
String intentItem = bundleData.getString("intentKey");
ListElementsArrayList.add(intentItem);
addBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
ListElementsArrayList.add(item);
adapter.notifyDataSetChanged();
}
});
}
}
Any Help would be Greatly Appreciated, Thank you.
You have to change this :
Intent i = new Intent(this, listPageActivty.class);
i.putExtra("intentKey",geofenceTransitionDetails);
to this :
Intent i = new Intent(this, listPageActivty.class);
i.putExtra("intentKey",geofenceTransitionDetails);
this.startActivity(i);
I think you just left the startActivity()
And in the other Activity you get the value like this :
String GeoTransitionDetails = getIntent().getExtras().getString("intentKey");
You are nowhere starting listPageActivty activity
Replace
Intent i = new Intent(this, listPageActivty.class);
i.putExtra("intentKey",geofenceTransitionDetails);
with
Intent i = new Intent(getBaseContext(), listPageActivty.class);
i.putExtra("intentKey",geofenceTransitionDetails);
getApplication().startActivity(dialogIntent);
I am trying to develop an Android application, which can access the current location of my phone and send it to my friend with URL.
So I use location object mLocation to access latitude and longitude of my location. FectchAddressIntentService.java is a service to obtain location address.
But it gives an error:
java.lang.IllegalArguementException:Attempt to invoke virtual method 'double android.Location.getlatitude()' on a null object reference
Here is the code of my MainActivity.java:
public class MainActivity extends AppCompatActivity implements
ConnectionCallbacks, OnConnectionFailedListener {
protected static final String TAG = "main-activity";
protected static final String ADDRESS_REQUESTED_KEY = "address-request-pending";
protected static final String LOCATION_ADDRESS_KEY = "location-address";
protected String message;
protected String phoneNo = "1234567890";
public void sendMessage() {
try {
SmsManager smsManager = SmsManager.getDefault();
smsManager.sendTextMessage(phoneNo, null, message, null, null);
Toast.makeText(MainActivity.this,"Sending SMS",Toast.LENGTH_LONG).show();
}
catch (Exception e)
{
Toast.makeText(MainActivity.this,e.toString(),Toast.LENGTH_LONG);
}
}
public void startGuardianActivity(){
Intent intentViewGuardian = new Intent(this, Guardians.class);
startActivity(intentViewGuardian);
}
/**
* Provides the entry point to Google Play services.
*/
protected GoogleApiClient mGoogleApiClient;
/**
* Represents a geographical location.
*/
protected Location mLastLocation;
protected String latitude;
protected String longitude;
/**
* Tracks whether the user has requested an address. Becomes true when the user requests an
* address and false when the address (or an error message) is delivered.
* The user requests an address by pressing the Fetch Address button. This may happen
* before GoogleApiClient connects. This activity uses this boolean to keep track of the
* user's intent. If the value is true, the activity tries to fetch the address as soon as
* GoogleApiClient connects.
*/
protected boolean mAddressRequested;
/**
* The formatted location address.
*/
protected String mAddressOutput;
/**
* Receiver registered with this activity to get the response from FetchAddressIntentService.
*/
private AddressResultReceiver mResultReceiver;
/**
* Kicks off the request to fetch an address when pressed.
*/
Button btnAlert;
Button btnAddGuardian;
Button btnRemoveGuardian;
Button btnViewGuardians;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_activity);
mResultReceiver = new AddressResultReceiver(new Handler());
btnAlert = (Button) findViewById(R.id.btn_Alert);
btnAddGuardian = (Button) findViewById(R.id.btn_add_guardian);
btnRemoveGuardian = (Button) findViewById(R.id.btn_remove_guardian);
btnViewGuardians = (Button) findViewById(R.id.btn_view_guardians);
btnAddGuardian.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
}
});
btnRemoveGuardian.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
}
});
btnViewGuardians.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
startGuardianActivity();
}
});
// Set defaults, then update using values stored in the Bundle.
mAddressRequested = false;
mAddressOutput = "";
updateValuesFromBundle(savedInstanceState);
updateUIWidgets();
buildGoogleApiClient();
}
/**
* Updates fields based on data stored in the bundle.
*/
private void updateValuesFromBundle(Bundle savedInstanceState) {
if (savedInstanceState != null) {
// Check savedInstanceState to see if the address was previously requested.
if (savedInstanceState.keySet().contains(ADDRESS_REQUESTED_KEY)) {
mAddressRequested = savedInstanceState.getBoolean(ADDRESS_REQUESTED_KEY);
}
// Check savedInstanceState to see if the location address string was previously found
// and stored in the Bundle. If it was found, display the address string in the UI.
if (savedInstanceState.keySet().contains(LOCATION_ADDRESS_KEY)) {
mAddressOutput = savedInstanceState.getString(LOCATION_ADDRESS_KEY);
displayAddressOutput();
}
}
}
/**
* Builds a GoogleApiClient. Uses {#code #addApi} to request the LocationServices API.
*/
protected synchronized void buildGoogleApiClient() {
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
}
/**
* Runs when user clicks the Fetch Address button. Starts the service to fetch the address if
* GoogleApiClient is connected.
*/
public void fetchAddressButtonHandler(View view) {
// We only start the service to fetch the address if GoogleApiClient is connected.
if (mGoogleApiClient.isConnected() && mLastLocation != null) {
startIntentService();
}
// If GoogleApiClient isn't connected, we process the user's request by setting
// mAddressRequested to true. Later, when GoogleApiClient connects, we launch the service to
// fetch the address. As far as the user is concerned, pressing the Fetch Address button
// immediately kicks off the process of getting the address.
mAddressRequested = true;
updateUIWidgets();
}
#Override
protected void onStart() {
super.onStart();
mGoogleApiClient.connect();
}
#Override
protected void onStop() {
super.onStop();
if (mGoogleApiClient.isConnected()) {
mGoogleApiClient.disconnect();
}
}
/**
* Runs when a GoogleApiClient object successfully connects.
*/
#Override
public void onConnected(Bundle connectionHint) {
// Gets the best and most recent location currently available, which may be null
// in rare cases when a location is not available.
try {
mLastLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
latitude = String.valueOf(mLastLocation.getLatitude());
longitude = String.valueOf(mLastLocation.getLongitude());
}
catch(Exception e)
{
Toast.makeText(MainActivity.this,e.toString(),Toast.LENGTH_LONG).show();
}
try {
if (mLastLocation != null) {
if (!Geocoder.isPresent()) {
Toast.makeText(this, R.string.no_geocoder_available, Toast.LENGTH_LONG).show();
return;
}
}
}
catch(Exception e)
{
Toast.makeText(MainActivity.this,e.toString(),Toast.LENGTH_LONG).show();
}
// It is possible that the user presses the button to get the address before the
// GoogleApiClient object successfully connects. In such a case, mAddressRequested
// is set to true, but no attempt is made to fetch the address (see
// fetchAddressButtonHandler()) . Instead, we start the intent service here if the
// user has requested an address, since we now have a connection to GoogleApiClient.
if (mAddressRequested) {
startIntentService();
}
}
/**
* Creates an intent, adds location data to it as an extra, and starts the intent service for
* fetching an address.
*/
protected void startIntentService() {
// Create an intent for passing to the intent service responsible for fetching the address.
Intent intent = new Intent(this, FetchAddressIntentService.class);
// Pass the result receiver as an extra to the service.
intent.putExtra(Constants.RECEIVER, mResultReceiver);
// Pass the location data as an extra to the service.
intent.putExtra(Constants.LOCATION_DATA_EXTRA, mLastLocation);
// Start the service. If the service isn't already running, it is instantiated and started
// (creating a process for it if needed); if it is running then it remains running. The
// service kills itself automatically once all intents are processed.
startService(intent);
}
#Override
public void onConnectionFailed(ConnectionResult result) {
// Refer to the javadoc for ConnectionResult to see what error codes might be returned in
// onConnectionFailed.
Log.i(TAG, "Connection failed: ConnectionResult.getErrorCode() = " + result.getErrorCode());
}
#Override
public void onConnectionSuspended(int cause) {
// The connection to Google Play services was lost for some reason. We call connect() to
// attempt to re-establish the connection.
Log.i(TAG, "Connection suspended");
mGoogleApiClient.connect();
}
/**
* Updates the address in the UI.
*/
protected void displayAddressOutput() {
sendMessage();
}
private void updateUIWidgets() {
if (mAddressRequested) {
btnAlert.setEnabled(false);
} else {
btnAlert.setEnabled(true);
}
}
/**
* Shows a toast with the given text.
*/
protected void showToast(String text) {
Toast.makeText(this, text, Toast.LENGTH_SHORT).show();
}
#Override
public void onSaveInstanceState(Bundle savedInstanceState) {
// Save whether the address has been requested.
savedInstanceState.putBoolean(ADDRESS_REQUESTED_KEY, mAddressRequested);
// Save the address string.
savedInstanceState.putString(LOCATION_ADDRESS_KEY, mAddressOutput);
super.onSaveInstanceState(savedInstanceState);
}
/**
* Receiver for data sent from FetchAddressIntentService.
*/
class AddressResultReceiver extends ResultReceiver {
public AddressResultReceiver(Handler handler) {
super(handler);
}
/**
* Receives data sent from FetchAddressIntentService and updates the UI in MainActivity.
*/
#Override
protected void onReceiveResult(int resultCode, Bundle resultData) {
// Display the address string or an error message sent from the intent service.
mAddressOutput = resultData.getString(Constants.RESULT_DATA_KEY);
message = "I am in DANGER!!I need your help #"+mAddressOutput+" link: http://maps.google.com/?q="+latitude+","+longitude;
displayAddressOutput();
// Show a toast message if an address was found.
if (resultCode == Constants.SUCCESS_RESULT) {
showToast(getString(R.string.address_found));
}
mAddressRequested = false;
updateUIWidgets();
}
}
}
I tried to convert
latitude = String.valueOf(mLastLocation.getLatitude());
to
longitude = String.valueOf(mLastLocation.getLongitude());
But didn't work.
I don't know what this error is, I don`t know what NullPointerException is,
I tried to follow other Questions on Stack Overflow of similar type but didn't solve problem, Can anyone help me to get through this?
Even if you feel it might be a duplicate of other question, tell me how it is or how they are related & how to solve my problem. Thanks in advance.:-)
The error means the valiable mLastLocation is null.
So the result of this line:
mLastLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
is null. I think you should null check before these lines:
latitude = String.valueOf(mLastLocation.getLatitude());
longitude = String.valueOf(mLastLocation.getLongitude());
Because they are calling methods of mLastLocation.
That is like:
if (mLastLocation == null || !Geocoder.isPresent()) {
Toast.makeText(this, R.string.no_geocoder_available, Toast.LENGTH_LONG).show();
return;
}
latitude = String.valueOf(mLastLocation.getLatitude());
longitude = String.valueOf(mLastLocation.getLongitude());
I have made two geofences by adding the coordinates from a sqlite table. It does create the geofences on the map and transitions also do occur.
My problem is that all the transitions trigger the same broadcast, this means no matter what two geofences I enter, it shows the same notification.
How do I get location specific messages?
I have used this line of code to get the triggered fence's ID and this works properly, but it also gives unwanted things such as the longitude, latitude and radius. How do I extract only the ID from this?
List<Geofence> ab = LocationClient.getTriggeringGeofences(intent);
This is the relevant part of the code.
#Override
public void onConnected(Bundle arg0) {
mClient.requestLocationUpdates(mRequest, this);
SQLiteDatabase db = database.getWritableDatabase();
String[] columns = {PromoDatabase.LID,PromoDatabase.lRestuarantID,PromoDatabase.lBranchID,PromoDatabase.Latitude,PromoDatabase.Longitude};
Cursor cursor = db.query(PromoDatabase.LOCATION_TABLE, columns, null, null, null, null, null);
String RestuarantName = null;
while(cursor.moveToNext()) //create the two geofences with with help of sqlite table
{
String LocationID = cursor.getString(0);
String RestuarantID = cursor.getString(1);
double latitude = cursor.getDouble(3);
double longitude = cursor.getDouble(4);
RestuarantName = getData(RestuarantID); //get the restuarant name by giving the RestuarantID
float radius = 800;
// Build a Geofence
Geofence fence = new Geofence.Builder()
.setRequestId(LocationID)
.setCircularRegion(latitude, longitude, radius)
.setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER)
.setExpirationDuration(Geofence.NEVER_EXPIRE)
.build();
mList.add(fence);
googleMap.addMarker( new MarkerOptions()
.position( new LatLng(latitude, longitude) )
.title(RestuarantName+": Fence " + LocationID)
.snippet("Radius: " + radius) ).showInfoWindow();
circleOptions = new CircleOptions()
.center( new LatLng(latitude, longitude) )
.radius( radius )
.fillColor(0x40ff0000)
.strokeColor(Color.TRANSPARENT)
.strokeWidth(2);
googleMap.addCircle(circleOptions);
}
// Method 2: Using Broadcast
Intent intent = new Intent();
intent.setAction(GeofenceEventReceiver.GEOFENCE_EVENTS); // Specify the action, a.k.a. receivers
intent.addCategory(Intent.CATEGORY_DEFAULT);
intent.putExtra("Location", "KFC");
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
// Send out the Geofence request
mClient.addGeofences(mList, pendingIntent, this);
}
// Broadcast receiver used to receive broadcast sent from the GeofenceIntentService
public class GeofenceEventReceiver extends BroadcastReceiver {
public static final String GEOFENCE_EVENTS = "com.Drogo.proto.GeofenceEvents";
#Override
public void onReceive(Context context, Intent intent) {
String locationInfo = "Arraived at " + intent.getStringExtra("Location");
List<Geofence> BreachedGeofence = LocationClient.getTriggeringGeofences(intent);
Toast.makeText(context, locationInfo + BreachedGeofence, Toast.LENGTH_LONG).show();
notifyMe(context,intent, locationInfo); //this will basically give me a notification through the notification manager.
}
Use
List <Geofence> triggerList = getTriggeringGeofences(intent);
String[] triggerIds = new String[geofenceList.size()];
for (int i = 0; i < triggerIds.length; i++) {
triggerIds[i] = triggerList.get(i).getRequestId();
}
taken from the Android documentation here.
Did you want something different from that?