How to solve geofence mock_location error? - android

so im running this sample app i got on github which deals with google maps and geo fences: https://github.com/androidfu/GeofenceExample
And when I run the code I get this error : Caused by: java.lang.SecurityException: com.androidfu.example.geofences from uid 10170 not allowed to perform MOCK_LOCATION
Here is the code for the class followed by the stack trace. Hope you guys can give me some insight. Also i have mock location in manifest. The error is coming from the onResume() method.
public class MapsActivity extends FragmentActivity implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, View.OnClickListener, ResultCallback<Status> {
public static final String TAG = MapsActivity.class.getSimpleName();
private static final long LOCATION_ITERATION_PAUSE_TIME = 1000;
private static final int NUMBER_OF_LOCATION_ITERATIONS = 10;
private GoogleMap googleMap; // Might be null if Google Play services APK is not available.
private MyPlaces happyPlace;
private MyPlaces home;
private List<Geofence> myFences = new ArrayList<>();
private GoogleApiClient googleApiClient;
private PendingIntent geofencePendingIntent;
private UpdateLocationRunnable updateLocationRunnable;
private LocationManager locationManager;
private int marker = 0;
private Location lastLocation;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_maps);
ImageButton happyPlaceBtn = (ImageButton) findViewById(R.id.ib_happy_place);
happyPlaceBtn.setOnClickListener(this);
ImageButton homeBtn = (ImageButton) findViewById(R.id.ib_home);
homeBtn.setOnClickListener(this);
ImageButton resetBtn = (ImageButton) findViewById(R.id.ib_reset);
resetBtn.setOnClickListener(this);
setUpMapIfNeeded();
}
/**
* Called when a view has been clicked.
*
* #param v The view that was clicked.
*/
#Override
public void onClick(View v) {
MyPlaces place;
switch (v.getId()) {
case R.id.ib_happy_place:
Toast.makeText(this, "You Clicked Happy Place", Toast.LENGTH_SHORT).show();
place = happyPlace;
moveToLocation(place);
break;
case R.id.ib_home:
Toast.makeText(this, "You Clicked Home", Toast.LENGTH_SHORT).show();
place = home;
moveToLocation(place);
break;
case R.id.ib_reset:
Toast.makeText(this, "Resetting Our Map", Toast.LENGTH_SHORT).show();
if (updateLocationRunnable != null) {
updateLocationRunnable.interrupt();
}
googleApiClient.disconnect();
googleMap.clear();
myFences.clear();
setUpMap();
break;
}
}
#Override
protected void onResume() {
super.onResume();
setUpMapIfNeeded();
this.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
Log.i(TAG, "Setup MOCK Location Providers");
locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
Log.i(TAG, "GPS Provider");
locationManager.addTestProvider(LocationManager.GPS_PROVIDER, false, true, false, false, false, false, false, Criteria.POWER_HIGH, Criteria.ACCURACY_FINE);
locationManager.setTestProviderEnabled(LocationManager.GPS_PROVIDER, true);
Log.i(TAG, "Network Provider");
locationManager.addTestProvider(LocationManager.NETWORK_PROVIDER, true, false, true, false, false, false, false, Criteria.POWER_MEDIUM, Criteria.ACCURACY_FINE);
locationManager.setTestProviderEnabled(LocationManager.NETWORK_PROVIDER, true);
}
#Override
protected void onPause() {
this.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
// Interrupt our runnable if we're going into the background or exiting
if (updateLocationRunnable != null) {
updateLocationRunnable.interrupt();
}
Log.i(TAG, "Cleanup Our Fields");
locationManager.removeTestProvider(LocationManager.GPS_PROVIDER);
locationManager.removeTestProvider(LocationManager.NETWORK_PROVIDER);
locationManager = null;
updateLocationRunnable = null;
super.onPause();
}
#Override
protected void onStop() {
googleApiClient.disconnect();
super.onStop();
}
/**
* Sets up the map if it is possible to do so (i.e., the Google Play services APK is correctly
* installed) and the map has not already been instantiated.. This will ensure that we only ever
* call {#link #setUpMap()} once when {#link #googleMap} is not null.
* <p/>
* If it isn't installed {#link SupportMapFragment} (and
* {#link com.google.android.gms.maps.MapView MapView}) will show a prompt for the user to
* install/update the Google Play services APK on their device.
* <p/>
* A user can return to this FragmentActivity after following the prompt and correctly
* installing/updating/enabling the Google Play services. Since the FragmentActivity may not
* have been completely destroyed during this process (it is likely that it would only be
* stopped or paused), {#link #onCreate(Bundle)} may not be called again so we should call this
* method in {#link #onResume()} to guarantee that it will be called.
*/
private void setUpMapIfNeeded() {
// Do a null check to confirm that we have not already instantiated the map.
if (googleMap == null) {
// Try to obtain the map from the SupportMapFragment.
googleMap = ((SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map)).getMap();
// Check if we were successful in obtaining the map.
if (googleMap != null) {
setUpMap();
}
}
}
/**
* This is where we can add markers or lines, add listeners or move the camera.
* <p/>
* This should only be called once and when we are sure that {#link #googleMap} is not null.
*/
private void setUpMap() {
googleMap.setBuildingsEnabled(true);
// PRES 1
/*
1. Create a "Place" that will become a Geofence
2. Add a place marker on our Map
3. Add our place to our list of Geofences
4. Repeat for each place
*/
// Add a place with a Geofence
happyPlace = new MyPlaces("Pier # Folly Beach", "This is my Happy Place!", new LatLng(32.652411, -79.938063), 10000, 10, R.drawable.ic_palm_tree);
addPlaceMarker(happyPlace);
addFence(happyPlace);
// Add a place with a Geofence
// Work 39.3336585, -84.3146718
// Home 39.2697455, -84.269921
home = new MyPlaces("Home", "This is where I live.", new LatLng(39.3336585, -84.3146718), 10000, 10, R.drawable.ic_home);
addPlaceMarker(home);
addFence(home);
// Add a place w/o a Geofence
MyPlaces charleston = new MyPlaces("Charleston, SC", "This is where I want to live!", new LatLng(32.8210454, -79.9704779), 0, 10, R.drawable.ic_heart);
addPlaceMarker(charleston);
addFence(charleston);
/*
After all your places have been created and markers added you can monitor your fences.
*/
monitorFences(myFences);
googleMap.setOnMapClickListener(new GoogleMap.OnMapClickListener() {
#Override
public void onMapClick(LatLng latLng) {
if (updateLocationRunnable != null && updateLocationRunnable.isAlive() && !updateLocationRunnable.isInterrupted()) {
updateLocationRunnable.interrupt();
}
updateLocationRunnable = new UpdateLocationRunnable(locationManager, latLng);
updateLocationRunnable.start();
MyPlaces touchedPlace = new MyPlaces(String.format("Marker %1$d", ++marker), "", latLng, 65, 12, 0);
addPlaceMarker(touchedPlace);
}
});
}
/**
* Add a map marker at the place specified.
*
* #param place the place to take action on
*/
private void addPlaceMarker(MyPlaces place) {
MarkerOptions markerOptions = new MarkerOptions();
markerOptions.position(place.getCoordinates())
.title(place.getTitle());
if (!TextUtils.isEmpty(place.getSnippet())) {
markerOptions.snippet(place.getSnippet());
}
if (place.getIconResourceId() > 0) {
markerOptions.icon(BitmapDescriptorFactory.fromResource(place.getIconResourceId()));
}
googleMap.addMarker(markerOptions);
drawGeofenceAroundTarget(place);
}
/**
* If our place has a fence radius greater than 0 then draw a circle around it.
*
* #param place the place to take action on
*/
private void drawGeofenceAroundTarget(MyPlaces place) {
if (place.getFenceRadius() <= 0) {
// Nothing to draw
return;
}
CircleOptions circleOptions = new CircleOptions();
circleOptions.center(place.getCoordinates());
circleOptions.fillColor(Color.argb(0x55, 0x00, 0x00, 0xff));
circleOptions.strokeColor(Color.argb(0xaa, 0x00, 0x00, 0xff));
circleOptions.radius(place.getFenceRadius());
googleMap.addCircle(circleOptions);
}
/**
* Update our map's location to the place specified.
*
* #param place the place to take action on
*/
private void moveToLocation(final MyPlaces place) {
// Move the camera instantly to "place" with a zoom of 5.
if (place.getTitle().equals("Charleston, SC")) {
googleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(place.getCoordinates(), place.getDefaultZoomLevel()));
}
// Fly to our new location and then set the correct zoom level for the given place.
googleMap.animateCamera(CameraUpdateFactory.newLatLng(place.getCoordinates()), new GoogleMap.CancelableCallback() {
#Override
public void onFinish() {
googleMap.animateCamera(CameraUpdateFactory.zoomTo(place.getDefaultZoomLevel()), 2000, null);
}
#Override
public void onCancel() {
// Nothing to see here.
}
});
}
/**
* If our place has a fence radius > 0 then add it to our monitored fences.
*
* #param place the place to take action on
*/
private void addFence(MyPlaces place) {
if (place.getFenceRadius() <= 0) {
// Nothing to monitor
return;
}
Geofence geofence = new Geofence.Builder()
.setCircularRegion(place.getCoordinates().latitude, place.getCoordinates().longitude, place.getFenceRadius())
.setRequestId(place.getTitle()) // every fence must have an ID
.setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER | Geofence.GEOFENCE_TRANSITION_EXIT) // can also have DWELL
.setExpirationDuration(Geofence.NEVER_EXPIRE) // how long do we care about this geofence?
//.setLoiteringDelay(60000) // 1 min.
.build();
myFences.add(geofence);
}
/**
* Connect our GoogleApiClient so we can begin monitoring our fences.
*
* #param fences our list of Geofences to monitor
*/
private void monitorFences(List<Geofence> fences) {
if (fences.isEmpty()) {
throw new RuntimeException("No fences to monitor. Call addPlaceMarker() First.");
}
// PRES 2
googleApiClient = new GoogleApiClient.Builder(this)
.addApi(LocationServices.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
googleApiClient.connect();
}
#Override
public void onConnected(Bundle bundle) {
/*
TODO
1. Display a spinner in the progress bar while we're waiting for location
2. When connected & not null update map position to location
3. If location null try again once every 10 seconds until we get an answer or quit after x minutes
4. ?
*/
Toast.makeText(this, "GoogleApiClient Connected", Toast.LENGTH_SHORT).show();
lastLocation = LocationServices.FusedLocationApi.getLastLocation(googleApiClient);
String lastLocationMessage;
if (lastLocation == null) {
lastLocationMessage = "Last Location is NULL";
moveToLocation(home);
} else {
lastLocationMessage = String.format("Last Location (%1$s, %2$s)", lastLocation.getLatitude(), lastLocation.getLongitude());
moveToLocation(new MyPlaces("Last Location", "I am here.", new LatLng(lastLocation.getLatitude(), lastLocation.getLongitude()), 0, 13, 0));
}
Toast.makeText(this, lastLocationMessage, Toast.LENGTH_SHORT).show();
// PRES 3
geofencePendingIntent = getRequestPendingIntent();
PendingResult<Status> result = LocationServices.GeofencingApi.addGeofences(googleApiClient, myFences, geofencePendingIntent);
result.setResultCallback(this);
}
#Override
public void onConnectionSuspended(int i) {
Toast.makeText(this, "GoogleApiClient Connection Suspended", Toast.LENGTH_SHORT).show();
}
#Override
public void onConnectionFailed(ConnectionResult connectionResult) {
Toast.makeText(this, "GoogleApiClient Connection Failed", Toast.LENGTH_SHORT).show();
}
#Override
public void onResult(Status status) {
String toastMessage;
// PRES 4
if (status.isSuccess()) {
toastMessage = "Success: We Are Monitoring Our Fences";
} else {
toastMessage = "Error: We Are NOT Monitoring Our Fences";
}
Toast.makeText(this, toastMessage, Toast.LENGTH_SHORT).show();
}
/**
* Returns the current PendingIntent to the caller.
*
* #return The PendingIntent used to create the current set of geofences
*/
public PendingIntent getRequestPendingIntent() {
return createRequestPendingIntent();
}
/**
* Get a PendingIntent to send with the request to add 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 createRequestPendingIntent() {
if (geofencePendingIntent != null) {
return geofencePendingIntent;
} else {
Intent intent = new Intent(this, GeofenceTransitionReceiver.class);
intent.setAction("geofence_transition_action");
return PendingIntent.getBroadcast(this, R.id.geofence_transition_intent, intent, PendingIntent.FLAG_UPDATE_CURRENT);
}
}
// /////////////////////////////////////////////////////////////////////////////////////////
// // UpdateLocationRunnable //
// /////////////////////////////////////////////////////////////////////////////////////////
private Location createMockLocation(String locationProvider, double latitude, double longitude) {
Location location = new Location(locationProvider);
location.setLatitude(latitude);
location.setLongitude(longitude);
location.setAccuracy(1.0f);
location.setTime(System.currentTimeMillis());
/*
setElapsedRealtimeNanos() was added in API 17
*/
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
location.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos());
}
try {
Method locationJellyBeanFixMethod = Location.class.getMethod("makeComplete");
if (locationJellyBeanFixMethod != null) {
locationJellyBeanFixMethod.invoke(location);
}
} catch (Exception e) {
// There's no action to take here. This is a fix for Jelly Bean and no reason to report a failure.
}
return location;
}
// /////////////////////////////////////////////////////////////////////////////////////////
// // CreateMockLocation //
// /////////////////////////////////////////////////////////////////////////////////////////
class UpdateLocationRunnable extends Thread {
private final LocationManager locMgr;
private final LatLng latlng;
Location mockGpsLocation;
Location mockNetworkLocation;
UpdateLocationRunnable(LocationManager locMgr, LatLng latlng) {
this.locMgr = locMgr;
this.latlng = latlng;
}
/**
* Starts executing the active part of the class' code. This method is
* called when a thread is started that has been created with a class which
* implements {#code Runnable}.
*/
#Override
public void run() {
try {
Log.i(TAG, String.format("Setting Mock Location to: %1$s, %2$s", latlng.latitude, latlng.longitude));
/*
Location can be finicky. Iterate over our desired location every second for
NUMBER_OF_LOCATION_ITERATIONS seconds to help it figure out where we want it to
be.
*/
for (int i = 0; !isInterrupted() && i <= NUMBER_OF_LOCATION_ITERATIONS; i++) {
mockGpsLocation = createMockLocation(LocationManager.GPS_PROVIDER, latlng.latitude, latlng.longitude);
locMgr.setTestProviderLocation(LocationManager.GPS_PROVIDER, mockGpsLocation);
mockNetworkLocation = createMockLocation(LocationManager.NETWORK_PROVIDER, latlng.latitude, latlng.longitude);
locMgr.setTestProviderLocation(LocationManager.NETWORK_PROVIDER, mockNetworkLocation);
Thread.sleep(LOCATION_ITERATION_PAUSE_TIME);
}
} catch (InterruptedException e) {
Log.i(TAG, "Interrupted.");
// Do nothing. We expect this to happen when location is successfully updated.
} finally {
Log.i(TAG, "Done moving location.");
}
}
}
}
stack trace:
09-26 11:08:07.870 10417-10417/com.androidfu.example.geofences E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.androidfu.example.geofences, PID: 10417
java.lang.RuntimeException: Unable to resume activity {com.androidfu.example.geofences/com.androidfu.example.geofences.GeofenceExampleLauncher}: java.lang.SecurityException: com.androidfu.example.geofences from uid 10170 not allowed to perform MOCK_LOCATION
at android.app.ActivityThread.performResumeActivity(ActivityThread.java:3121)
at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:3152)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2499)
at android.app.ActivityThread.access$900(ActivityThread.java:157)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1356)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5525)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:730)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:620)
Caused by: java.lang.SecurityException: com.androidfu.example.geofences from uid 10170 not allowed to perform MOCK_LOCATION
at android.os.Parcel.readException(Parcel.java:1599)
at android.os.Parcel.readException(Parcel.java:1552)
at android.location.ILocationManager$Stub$Proxy.addTestProvider(ILocationManager.java:1096)
at android.location.LocationManager.addTestProvider(LocationManager.java:1298)
at com.androidfu.example.geofences.MapsActivity.onResume(MapsActivity.java:120)
at android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1258)
at android.app.Activity.performResume(Activity.java:6347)
at android.app.ActivityThread.performResumeActivity(ActivityThread.java:3110)
at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:3152) 
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2499) 
at android.app.ActivityThread.access$900(ActivityThread.java:157) 
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1356) 
at android.os.Handler.dispatchMessage(Handler.java:102) 
at android.os.Looper.loop(Looper.java:148) 
at android.app.ActivityThread.main(ActivityThread.java:5525) 
at java.lang.reflect.Method.invoke(Native Method) 
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:730) 
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:620) 

I guess you have not allowed mock locations from phones developer options.
It should be under Debug section.

Related

Not Able To Upgrade Gps settings to high Accuracy using FusedLocationProvider In some devices

I am using SettingsApi and FusedLocationProvider to upgrade Gps settings and getting location updates, I want High accuracy location updates for that I am showing Turn on gps dialog using SettingsApi to upgrade GPS settings to High Accuracy but in some devices (like Mi and Gionee) even if the user has clicked OK button in Turn On Gps Dialog I am getting RESULT_CANCELED on onActivityResult while everything is working perfectly fine in other devices like Motorola, Lenovo
When User is Clicking On in Turn On Gps dialog
If Gps is Off then it is turned On and gets set to Device Only Mode (Gps Only Mode)
If Gps is On then Gps is turned Off and I am getting RESULT_CANCELED on onActivityResult in both the cases
Here's My Code
LocationHelper
public class LocationHelper {
private static final String TAG = LocationHelper.class.getSimpleName();
private long updateIntervalInMilliseconds = 10000;
private long fastestUpdateIntervalInMilliseconds = updateIntervalInMilliseconds / 2;
private FusedLocationProviderClient mFusedLocationClient;
private SettingsClient mSettingsClient;
private LocationRequest mLocationRequest;
private LocationSettingsRequest mLocationSettingsRequest;
private LocationCallback mLocationCallback;
private Boolean mRequestingLocationUpdates = false;
private int requiredGpsPriority = LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY;
public LocationHelper(Context mContext) {
mFusedLocationClient = LocationServices.getFusedLocationProviderClient(mContext);
mSettingsClient = LocationServices.getSettingsClient(mContext);
}
/**
* Sets required gps priority
* <p>
* Gps Priority can be
* <ul>
* <li>LocationRequest.PRIORITY_HIGH_ACCURACY</li>
* <li>LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY</li>
* <li>LocationRequest.PRIORITY_NO_POWER</li>
* <li>LocationRequest.PRIORITY_LOW_POWER</li>
* </ul>
* <p>
* default is LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY
*
* #param requiredGpsPriority gps priority
*/
public void setRequiredGpsPriority(int requiredGpsPriority) {
this.requiredGpsPriority = requiredGpsPriority;
}
/**
* Sets Update Interval also sets fastestUpdateIntervalInMilliseconds to half of updateIntervalInMilliseconds
* default is 10 seconds
*
* #param updateIntervalInMilliseconds update Interval
*/
public void setUpdateInterval(long updateIntervalInMilliseconds) {
this.updateIntervalInMilliseconds = updateIntervalInMilliseconds;
this.fastestUpdateIntervalInMilliseconds = updateIntervalInMilliseconds / 2;
}
/**
* Sets fastest Update Interval
* default is 5 seconds
*
* #param fastestUpdateIntervalInMilliseconds fastest update Interval
*/
public void setFastestUpdateIntervalInMilliseconds(long fastestUpdateIntervalInMilliseconds) {
this.fastestUpdateIntervalInMilliseconds = fastestUpdateIntervalInMilliseconds;
}
public void init() {
createLocationRequest();
buildLocationSettingsRequest();
}
public void setLocationCallback(LocationCallback locationCallback) {
this.mLocationCallback = locationCallback;
}
private void createLocationRequest() {
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(updateIntervalInMilliseconds);
mLocationRequest.setFastestInterval(fastestUpdateIntervalInMilliseconds);
mLocationRequest.setPriority(requiredGpsPriority);
}
private void buildLocationSettingsRequest() {
LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder();
builder.addLocationRequest(mLocationRequest);
builder.setAlwaysShow(true);
mLocationSettingsRequest = builder.build();
}
public boolean isRequestingForLocation() {
return mRequestingLocationUpdates;
}
public void checkForGpsSettings(GpsSettingsCheckCallback callback) {
if (mLocationSettingsRequest == null) {
throw new IllegalStateException("must call init() before check for gps settings");
}
// Begin by checking if the device has the necessary jobLocation settings.
mSettingsClient.checkLocationSettings(mLocationSettingsRequest)
.addOnSuccessListener(locationSettingsResponse -> callback.requiredGpsSettingAreAvailable())
.addOnFailureListener(e -> {
int statusCode = ((ApiException) e).getStatusCode();
switch (statusCode) {
case LocationSettingsStatusCodes.RESOLUTION_REQUIRED:
Log.i(TAG, "SuggestedLocation settings are not satisfied. notifying back to the requesting object ");
ResolvableApiException rae = (ResolvableApiException) e;
callback.requiredGpsSettingAreUnAvailable(rae);
break;
case LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE:
Log.i(TAG, "Turn On SuggestedLocation From Settings. ");
callback.gpsSettingsNotAvailable();
break;
}
});
}
/**
* Starts location updates from the FusedLocationApi.
* <p>
* Consider Calling {#link #stopLocationUpdates()} when you don't want location updates it helps in saving battery
* </p>
*/
public void startLocationUpdates() {
if (mLocationRequest == null) {
throw new IllegalStateException("must call init() before requesting location updates");
}
if (mLocationCallback == null) {
throw new IllegalStateException("no callback provided for delivering location updates,use setLocationCallback() for setting callback");
}
if (mRequestingLocationUpdates) {
Log.d(TAG, "startLocationUpdates: already requesting location updates, no-op.");
return;
}
Log.d(TAG, "startLocationUpdates: starting updates.");
mFusedLocationClient.requestLocationUpdates(mLocationRequest, mLocationCallback, Looper.myLooper())
.addOnCompleteListener(task -> mRequestingLocationUpdates = true);
}
public void stopLocationUpdates() {
if (!mRequestingLocationUpdates) {
Log.d(TAG, "stopLocationUpdates: updates never requested, no-op.");
return;
}
Log.d(TAG, "stopLocationUpdates: stopping location updates.");
mFusedLocationClient.removeLocationUpdates(mLocationCallback)
.addOnCompleteListener(task -> mRequestingLocationUpdates = false);
}
}
GpsSettingsCheckCallback
public interface GpsSettingsCheckCallback {
/**
* We don't have required Gps Settings
* ex For High Accuracy Locations We Need Gps In High Accuracy Settings
*
* How To show "Turn On Gps Dialog" ?
*
* From Activity :
* <code>status.startResolutionForResult(this , REQUEST_CHECK_SETTINGS);</code>
*
* From Fragment :
* <code>
* startIntentSenderForResult(status.getResolution().getIntentSender(), REQUEST_CHECK_SETTINGS, null, 0, 0, 0, null)
* </code>
*/
void requiredGpsSettingAreUnAvailable(ResolvableApiException status);
/**
* Everything's Good
*/
void requiredGpsSettingAreAvailable();
/**
* Gps Settings Are Unavailable redirect user to settings page to turn on location
*/
void gpsSettingsNotAvailable();
}
Activity Code
public class CheckGpsActivity extends AppCompatActivity {
public static final String TAG = CheckGpsActivity.class.getSimpleName();
public static final int REQUEST_LOCATION_SETTINGS_UPGRADE = 23;
private Button turnOnLocationUpdatesBtn, turnOffLocationBtn, checkForRequredGpsSettingBtn;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
LocationHelper locationHelper = new LocationHelper(this);
locationHelper.setRequiredGpsPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
locationHelper.init();
locationHelper.setLocationCallback(new LocationCallback() {
#Override
public void onLocationResult(LocationResult locationResult) {
super.onLocationResult(locationResult);
Location location = locationResult.getLocations().get(0);
if (location != null)
Log.d(TAG, "Gps Coords" + location.getLatitude() + "," + location.getLongitude());
}
});
turnOnLocationUpdatesBtn.setOnClickListener(view -> locationHelper.startLocationUpdates());
turnOffLocationBtn.setOnClickListener(view -> locationHelper.startLocationUpdates());
checkForRequredGpsSettingBtn.setOnClickListener(view -> {
locationHelper.checkForGpsSettings(new GpsSettingsCheckCallback() {
#Override
public void requiredGpsSettingAreUnAvailable(ResolvableApiException status) {
Log.d(TAG, "require gps settings upgrade");
try {
status.startResolutionForResult(CheckGpsActivity.this, REQUEST_LOCATION_SETTINGS_UPGRADE);
} catch (IntentSender.SendIntentException e) {
e.printStackTrace();
}
}
#Override
public void requiredGpsSettingAreAvailable() {
Log.d(TAG, "Gps Setting are just fine");
}
#Override
public void gpsSettingsNotAvailable() {
Log.d(TAG, "Gps Setting unavailable, redirect to settings");
}
});
});
}
#Override
protected void onActivityResult(int requestCode, int resultCode, #Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
//Result code I always get is 0 (RESULT_CANCELED) even if user clicked Ok in Turn On Location dialog
}
}
WorkAround #1: You can opt for
LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY - Faster Location Updates but location accuracy may be low
LocationRequest.PRIORITY_LOW_POWER - Slower or maybe No Location Updates (if indoor or underground)
WorkAround #2: Redirect User to Settings Page
Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
startActivityForResult(intent, REQUEST_UPDATE_GPS_SETTINGS_MANUALLY);

Track user location in Realtime using Polylines in Google Maps (Android)

I have some experience with Android, but am new to using the Google Maps API and Location Services. I am trying to show the user's movement on a MapFragment by moving the tracker and drawing a Polyline over where the user has been, sort of like MapMyRun.
From what I've seen on my debugger, I get a location after the Fragment resumes, and it is appended to the list of LatLngs. What I need is for the map to update every few seconds, or everytime the location changes by a tenth of a mile or so.
Here is what I have for the activity containing the MapFragment. My instinct tells me I need to do something inside of the the method handleNewLocation that would update the map...either that or perhaps do something in the LocationProvider that would update the location more often.
Any help, tips, or links would be greatly appreciated! My goal is to learn so that I understand how I can do this better in the future :)!
package com.seniorproject.trafton.trackrecordrace;
//Import statements not shown for readability
import...
public class MapsActivity extends AppCompatActivity implements LocationProvider.LocationCallback {
public static final String TAG = "cloudsTraf";
//MapsActivity.class.getSimpleName();
private GoogleMap mMap; // Might be null if Google Play services APK is not available.
private LocationProvider mLocationProvider;
//variable for toggle buttons
private boolean isRunning = false;
//ArrayList to store geopoints for current run
private ArrayList<LatLng> geoPoints;
//Array of distances
private ArrayList<Float> distances;
//total distance
private float totalDistance;
//polyline that represented the route
Polyline tracker;
/*Load up widgets for tracking */
private ImageButton mPlayButton;
private ImageButton mPauseButton;
private TextView mRunTimeText;
private TextView mRunSpeedText;
private TextView mRunDistText;
private TextView mRunCalsText;
private Boolean mIsPlayButtonClicked;
//Handler to control timer tracking
//Thank you to Nikos Maravitsas for the tutorial on timers
private Handler timeHandler = new Handler();
private long startTime = 0L;
long timeInMillis = 0L;
long timeSwapBuffer = 0L;
long updatedTime = 0L;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_maps);
setUpMapIfNeeded();
mLocationProvider = new LocationProvider(this, this);
geoPoints = new ArrayList<LatLng>(); //added
//Add in code to inflate the tracking modules
mRunTimeText = (TextView) findViewById(R.id.run_time_text);
mRunDistText = (TextView) findViewById(R.id.run_dist_text);
mRunSpeedText = (TextView) findViewById(R.id.run_speed_text);
Toolbar runToolbar= (Toolbar) findViewById(R.id.toolbar_run);
runToolbar.setTitle("Run on " + getDate());
runToolbar.setTitleTextColor(Color.WHITE);
setSupportActionBar(runToolbar);
}
//Inflate the menu for the toolbar
public boolean onCreateOptionsMenu(Menu menu) {
Log.e("XXX", "Menu created");
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.menu_maps_run, menu);
return super.onCreateOptionsMenu(menu);
}
//Handles possibilities of menu items being selected.
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle item selection
switch (item.getItemId()) {
case R.id.action_begin_run:
if (!isRunning) {
startTime = SystemClock.uptimeMillis();
timeHandler.postDelayed(updateTimerThread,0);
item.setIcon(R.drawable.ic_pause_white_24dp);
isRunning = true;
}
else {
timeSwapBuffer += timeInMillis;
timeHandler.removeCallbacks(updateTimerThread);
item.setIcon(R.drawable.ic_play_arrow_white_24dp);
isRunning = false;
}
return true;
case R.id.action_stop_run:
//stop run, save run, and transport user to the stats for that run
return true;
default:
return super.onOptionsItemSelected(item);
}
}
/*Code to update the timer, begins a new timer thread.*/
private Runnable updateTimerThread = new Runnable() {
public void run(){
timeInMillis = SystemClock.uptimeMillis() - startTime;
updatedTime = timeSwapBuffer + timeInMillis;
//Get integer value from time update and put into textView
int seconds = (int) (updatedTime/1000);
//need two seconds variables for formatting purposes.
int secs = seconds % 60;
int mins = (seconds / 60);
int hours = (mins / 60);
mRunTimeText.setText("" + hours + ":" +
String.format("%02d", mins) + ":" +
String.format("%02d", secs));
timeHandler.postDelayed(this, 0);
}
};
/* */
#Override
protected void onResume() {
super.onResume();
setUpMapIfNeeded();
mLocationProvider.connect();
}
#Override
protected void onPause() {
super.onPause();
mLocationProvider.disconnect();
}
/**
* Sets up the map if it is possible to do so (i.e., the Google Play services APK is correctly
* installed) and the map has not already been instantiated.. This will ensure that we only ever
* call {#link #setUpMap()} once when {#link #mMap} is not null.
* <p/>
* If it isn't installed {#link SupportMapFragment} (and
* {#link com.google.android.gms.maps.MapView MapView}) will show a prompt for the user to
* install/update the Google Play services APK on their device.
* <p/>
* A user can return to this FragmentActivity after following the prompt and correctly
* installing/updating/enabling the Google Play services. Since the FragmentActivity may not
* have been completely destroyed during this process (it is likely that it would only be
* stopped or paused), {#link #onCreate(Bundle)} may not be called again so we should call this
* method in {#link #onResume()} to guarantee that it will be called.
*/
private void setUpMapIfNeeded() {
// Do a null check to confirm that we have not already instantiated the map.
if (mMap == null) {
// Try to obtain the map from the SupportMapFragment.
mMap = ((SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map))
.getMap();
// Check if we were successful in obtaining the map.
if (mMap != null) {
setUpMap();
}
}
}
/**
* This should only be called once and when we are sure that {#link #mMap} is not null.
*/
private void setUpMap() {
//mMap.addMarker(new MarkerOptions().position(new LatLng(0, 0)).title("Marker"));
}
//handle new location
public void handleNewLocation(Location location) {
Log.d(TAG, location.toString());
double currentLatitude = location.getLatitude();
double currentLongitude = location.getLongitude();
LatLng latLng = new LatLng(currentLatitude, currentLongitude);
//Get the new geopoints to redraw the line on each iteration
geoPoints.add(latLng);
//get the latest distance update
if (geoPoints.size() > 2) {
calculateDistance();
}
//set the distance test
mRunDistText.setText(Float.toString(totalDistance) + " Meters");
mRunSpeedText.setText((location.getSpeed() + " m/s"));
//draw the polyline
drawRoute();
MarkerOptions options = new MarkerOptions()
.position(latLng)
.title("I am here!");
mMap.addMarker(options);
mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(latLng,15));
}
/*
*Methods to calculate metrics. All measurements returned are approximations.
*/
//returns the latest distance between geoPoints. Append to total number
public void calculateDistance(){
Location newLoc = new Location("Latest Location");
Location oldLoc = new Location("Last known Location");
LatLng newPt = geoPoints.get(geoPoints.size()- 1);
LatLng oldPt = geoPoints.get(geoPoints.size()-2);
distances.add(oldLoc.distanceTo(newLoc));
//add to the distance variable
totalDistance = totalDistance + oldLoc.distanceTo(newLoc);
Log.d(TAG, "distance between points is: " + oldLoc.distanceTo(newLoc));
}
//calculates the current KCals being burned
public void calculateKcals(){
}
//get today's date in a simple format
public String getDate(){
Date today = Calendar.getInstance().getTime();
SimpleDateFormat formatter = new SimpleDateFormat("EEE MMM dd");
String todaysDate = formatter.format(today);
return todaysDate;
}
//method to draw polyline. Uses the recorded geopoints.
public void drawRoute(){
mMap.clear();
PolylineOptions options = new PolylineOptions().width(5).color(android.R.color.holo_blue_dark).geodesic(true).visible(true);
for(int i = 0; i < geoPoints.size(); i++){
LatLng pt = geoPoints.get(i);
options.add(pt);
}
Log.d(TAG,"GeoPoints recorded: " + geoPoints);
mMap.addPolyline(options);
}
}
I'm grabbing the location in a different file (Because, y'know, modularity is good.).
If there is any additional data I can provide, I would be more than happy to include it!
package com.seniorproject.trafton.trackrecordrace;
import android.app.Activity;
import android.content.Context;
import android.content.IntentSender;
import android.location.Location;
import android.os.Bundle;
import android.util.Log;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.location.LocationListener;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationServices;
public class LocationProvider implements
GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener,
LocationListener {
public abstract interface LocationCallback {
public void handleNewLocation(Location location);
}
public static final String TAG = LocationProvider.class.getSimpleName();
/*
* Define a request code to send to Google Play services
* This code is returned in Activity.onActivityResult
*/
private final static int CONNECTION_FAILURE_RESOLUTION_REQUEST = 9000;
private LocationCallback mLocationCallback;
private Context mContext;
private GoogleApiClient mGoogleApiClient;
private LocationRequest mLocationRequest;
public LocationProvider(Context context, LocationCallback callback) {
mGoogleApiClient = new GoogleApiClient.Builder(context)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
mLocationCallback = callback;
// Create the LocationRequest object
mLocationRequest = LocationRequest.create()
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
.setInterval(3 * 1000) // 10 seconds, in milliseconds
.setFastestInterval(1 * 1000); // 1 second, in milliseconds
mContext = context;
}
public void connect() {
mGoogleApiClient.connect();
}
public void disconnect() {
if (mGoogleApiClient.isConnected()) {
LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);
mGoogleApiClient.disconnect();
}
}
#Override
public void onConnected(Bundle bundle) {
Log.i(TAG, "Location services connected.");
Location location = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
if (location == null) {
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);
}
else {
mLocationCallback.handleNewLocation(location);
}
}
#Override
public void onConnectionSuspended(int i) {
}
#Override
public void onConnectionFailed(ConnectionResult connectionResult) {
/*
* Google Play services can resolve some errors it detects.
* If the error has a resolution, try sending an Intent to
* start a Google Play services activity that can resolve
* error.
*/
if (connectionResult.hasResolution() && mContext instanceof Activity) {
try {
Activity activity = (Activity)mContext;
// Start an Activity that tries to resolve the error
connectionResult.startResolutionForResult(activity, CONNECTION_FAILURE_RESOLUTION_REQUEST);
/*
* Thrown if Google Play services canceled the original
* PendingIntent
*/
} catch (IntentSender.SendIntentException e) {
// Log the error
e.printStackTrace();
}
} else {
/*
* If no resolution is available, display a dialog to the
* user with the error.
*/
Log.i(TAG, "Location services connection failed with code " + connectionResult.getErrorCode());
}
}
#Override
public void onLocationChanged(Location location) {
mLocationCallback.handleNewLocation(location);
Log.i(TAG, "New location received ");
}
}
To draw a Polyline on the map do this in onLocationChanged
Polyline route = mMap.addPolyline(new PolylineOptions());
route.setPoints(mGeoPoints);`

Android Geofence Not Triggering, Causing GPS Activity, or Calling IntentService

So I've followed the documentation I found here: https://developer.android.com/training/location/geofencing.html
After implementing the tutorial I can see that the Geofence I'm testing with has been created and added. I get a success status.
My problem now is: the Geofence is added but my phone is showing no GPS activity and the Geofence isn't triggering the PendingIntent even though its been added successfully.
I declare the service in my manifest:
<service android:name=".journeytools.TraiNapIntentService"
android:exported="false"/>
And I have the following permission:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
The class adding the Geofence is:
public class SplashScreen extends Activity implements View.OnClickListener, ResultCallback<Status>,
GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener {
TextView miles, push, alarm;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.splash_screen);
buildGoogleApiClient();
System.out.println("Building Google Api Client");
if (GooglePlayServicesUtil.isGooglePlayServicesAvailable(getApplicationContext())
!= ConnectionResult.SUCCESS) {
//TODO Add something to post a message to the screen that the service isn't available
System.out.println("Service not Available");
} else {
System.out.println("Service Available");
miles = (TextView) findViewById(R.id.tvmiles);
push = (TextView) findViewById(R.id.tvpush);
alarm = (TextView) findViewById(R.id.tvalarm);
Button button = (Button)findViewById(R.id.button);
button.setOnClickListener(this);
}
}
ArrayList geoFenceList;
PendingIntent geoFencePendingIntent = null;
/**
* Provides the entry point to Google Play services.
*/
protected GoogleApiClient mGoogleApiClient;
#Override
public void onClick(View v) {
System.out.println("Onclick pressed");
DataGather data = new DataGather();
data.writePreferences(this, 5, false, true);
data.writeRecentJourney(this, "Wareham", "Poole");
double longitude = data.getGoingToLong(getBaseContext());
double latitude = data.getGoingToLat(getBaseContext());
float proximity = getProximity();
/*
* Add the geofence work.
*/
geoFenceList = new ArrayList();
geoFenceList.add(
new Geofence.Builder()
.setRequestId("Testing the addition")
.setCircularRegion(
latitude,
longitude,
proximity)
.setExpirationDuration(Geofence.NEVER_EXPIRE)
.setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER)
.build()
);
System.out.println("Added Geofence to Arraylist");
LocationServices.GeofencingApi.addGeofences(
mGoogleApiClient,
getGeofencingRequest(),
getGeofencePendingIntent()
).setResultCallback(this);
System.out.println("Added GeoFence");
}
#Override
protected void onStart() {
super.onStart();
mGoogleApiClient.connect();
}
#Override
protected void onStop() {
super.onStop();
mGoogleApiClient.disconnect();
}
/**
* 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 GeofencingRequest getGeofencingRequest() {
GeofencingRequest.Builder geoFencingRequestBuilder = new GeofencingRequest.Builder();
geoFencingRequestBuilder.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER);
geoFencingRequestBuilder.addGeofences(geoFenceList);
System.out.println("Returning geoFencingRequestBuilder.build()");
return geoFencingRequestBuilder.build();
}
/**
* Uses the users inserted information to derive the proximity setting.
* #return Returns a float of the proximity number.
*/
private float getProximity(){
DataGather dataGather = new DataGather();
String[] prefs = dataGather.getPreferences(this);
System.out.println("Returning Float" + Float.parseFloat(prefs[0]) * 1609.344);
return (float) (Float.parseFloat(prefs[0]) * 1609.344);
}
private PendingIntent getGeofencePendingIntent(){
Intent intent = new Intent(this, TraiNapIntentService.class);
System.out.println("Returning PendingIntent.getSerivce");
return PendingIntent.getService(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
}
/**
* TODO Finish this method
* #param status
*/
public void onResult(Status status) {
if (status.isSuccess()) {
System.out.println("Success status received");
} else {
System.out.println("Non-Success status received");
}
}
/**
* TODO Finish this method
* #param bundle
*/
#Override
public void onConnected(Bundle bundle) {
System.out.println("onConnected");
}
/**
* TODO Finish this method
* #param i
*/
#Override
public void onConnectionSuspended(int i) {
System.out.println("onConnectionSuspended");
}
/**
* TODO Finish this method
* #param connectionResult
*/
#Override
public void onConnectionFailed(ConnectionResult connectionResult) {
System.out.println("Connection Failed");
}
}
My code doesn't reach the IntentService so I haven't posted it up but I can if anyone is in need.
Any ideas on whats missing?
Something I found interesting about Google's geofence solution is that it won't show the GPS icon when it does a GPS poll, and it keeps power costs low by mainly making network location calls.
As for your problem, if you have a very small geofence (<50m radius), your location accuracy may be larger then your geofence, so it won't register an ingress event (which is the only one you are listening for). Try a larger geofence just to test your code.

Email address google maps app in a message to the mobile phone?

I am creating an app in android -studio , and I have a problem .
The app contains the Google Maps which shows us our location , but what really would make was that the push of a button , our location was sent by sms to a number of mobile phone , it will be possible ?
I created a demo app and it can:
Show your current location on the map as a marker.
Have a button. When you click it, it will create a SMS massage that you can send
your location via SMS.
Sample code:
public class MapsActivity extends FragmentActivity implements
GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener,
LocationListener,
ResultCallback<LocationSettingsResult>,
View.OnClickListener {
public static final String TAG = MapsActivity.class.getSimpleName();
/*
* Define a request code to send to Google Play services
* This code is returned in Activity.onActivityResult
*/
private final static int CONNECTION_FAILURE_RESOLUTION_REQUEST = 9000;
protected static final int REQUEST_CHECK_SETTINGS = 0x1;
private GoogleMap mMap; // Might be null if Google Play services APK is not available.
private GoogleApiClient mGoogleApiClient;
private LocationRequest mLocationRequest;
private LocationSettingsRequest mLocationSettingsRequest;
private Button btn_send_location;
private double mCurrentLatitude;
private double mCurrentLongitude;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_maps);
setUpMapIfNeeded();
btn_send_location = (Button) findViewById(R.id.send_my_location_btn);
btn_send_location.setOnClickListener(this);
long interval = 10 * 1000; // 10 seconds, in milliseconds
long fastestInterval = 1 * 1000; // 1 second, in milliseconds
float minDisplacement = 0;
// // Check if has GPS
LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
if (!locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
buildAlertMessageNoGps();
}
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
// Create the LocationRequest object
// mLocationRequest = LocationRequest.create()
// .setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY)
// .setInterval(interval)
// .setFastestInterval(fastestInterval)
// .setSmallestDisplacement(minDisplacement);
// Check if has GPS by using Google play service
// buildLocationSettingsRequest();
// checkLocationSettings();
}
#Override
protected void onResume() {
super.onResume();
setUpMapIfNeeded();
mGoogleApiClient.connect();
}
#Override
protected void onPause() {
super.onPause();
if (mGoogleApiClient.isConnected()) {
LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);
mGoogleApiClient.disconnect();
}
}
/**
* Sets up the map if it is possible to do so (i.e., the Google Play services APK is correctly
* installed) and the map has not already been instantiated.. This will ensure that we only ever
* call {#link #setUpMap()} once when {#link #mMap} is not null.
* <p/>
* If it isn't installed {#link SupportMapFragment} (and
* {#link com.google.android.gms.maps.MapView MapView}) will show a prompt for the user to
* install/update the Google Play services APK on their device.
* <p/>
* A user can return to this FragmentActivity after following the prompt and correctly
* installing/updating/enabling the Google Play services. Since the FragmentActivity may not
* have been completely destroyed during this process (it is likely that it would only be
* stopped or paused), {#link #onCreate(Bundle)} may not be called again so we should call this
* method in {#link #onResume()} to guarantee that it will be called.
*/
private void setUpMapIfNeeded() {
// Do a null check to confirm that we have not already instantiated the map.
if (mMap == null) {
// Try to obtain the map from the SupportMapFragment.
mMap = ((SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map))
.getMap();
}
}
private void handleNewLocation(Location location) {
Log.d(TAG, location.toString());
mCurrentLatitude = location.getLatitude();
mCurrentLongitude = location.getLongitude();
LatLng latLng = new LatLng(mCurrentLatitude, mCurrentLongitude);
//mMap.addMarker(new MarkerOptions().position(new LatLng(currentLatitude, currentLongitude)).title("Current Location"));
MarkerOptions options = new MarkerOptions()
.position(latLng)
.title("I am here!");
mMap.addMarker(options);
mMap.animateCamera(CameraUpdateFactory.newLatLngZoom(latLng, 15));
}
#Override
public void onConnected(Bundle bundle) {
Location location = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
if (location == null) {
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);
} else {
handleNewLocation(location);
}
}
#Override
public void onConnectionSuspended(int i) {
}
#Override
public void onConnectionFailed(ConnectionResult connectionResult) {
/*
* Google Play services can resolve some errors it detects.
* If the error has a resolution, try sending an Intent to
* start a Google Play services activity that can resolve
* error.
*/
if (connectionResult.hasResolution()) {
try {
// Start an Activity that tries to resolve the error
connectionResult.startResolutionForResult(this, CONNECTION_FAILURE_RESOLUTION_REQUEST);
/*
* Thrown if Google Play services canceled the original
* PendingIntent
*/
} catch (IntentSender.SendIntentException e) {
// Log the error
e.printStackTrace();
}
} else {
/*
* If no resolution is available, display a dialog to the
* user with the error.
*/
Log.i(TAG, "Location services connection failed with code " + connectionResult.getErrorCode());
}
}
#Override
public void onLocationChanged(Location location) {
handleNewLocation(location);
}
private void buildAlertMessageNoGps() {
final AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage("Your GPS seems to be disabled, do you want to enable it?")
.setCancelable(false)
.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
public void onClick(#SuppressWarnings("unused") final DialogInterface dialog, #SuppressWarnings("unused") final int id) {
startActivity(new Intent(android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS));
}
})
.setNegativeButton("No", new DialogInterface.OnClickListener() {
public void onClick(final DialogInterface dialog, #SuppressWarnings("unused") final int id) {
dialog.cancel();
}
});
final AlertDialog alert = builder.create();
alert.show();
}
/**
* Uses a {#link com.google.android.gms.location.LocationSettingsRequest.Builder} to build
* a {#link com.google.android.gms.location.LocationSettingsRequest} that is used for checking
* if a device has the needed location settings.
*/
protected void buildLocationSettingsRequest() {
LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder();
builder.addLocationRequest(mLocationRequest);
mLocationSettingsRequest = builder.build();
}
protected void checkLocationSettings() {
PendingResult<LocationSettingsResult> result =
LocationServices.SettingsApi.checkLocationSettings(
mGoogleApiClient,
mLocationSettingsRequest
);
result.setResultCallback(this);
}
#Override
public void onResult(LocationSettingsResult locationSettingsResult) {
final Status status = locationSettingsResult.getStatus();
switch (status.getStatusCode()) {
case LocationSettingsStatusCodes.SUCCESS:
// NO need to show the dialog;
break;
case LocationSettingsStatusCodes.RESOLUTION_REQUIRED:
// Location settings are not satisfied. Show the user a dialog
try {
// Show the dialog by calling startResolutionForResult(), and check the result
// in onActivityResult().
status.startResolutionForResult(this, REQUEST_CHECK_SETTINGS);
} catch (IntentSender.SendIntentException e) {
//unable to execute request
}
break;
case LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE:
// Location settings are inadequate, and cannot be fixed here. Dialog not created
break;
}
}
#Override
public void onClick(View v) {
Intent sendIntent = new Intent(Intent.ACTION_VIEW);
sendIntent.setData(Uri.parse("sms:"));
sendIntent.putExtra("sms_body", "My location at \nLatitude: " + mCurrentLatitude + " \nLongitude: " + mCurrentLongitude);
startActivity(sendIntent);
}
}
And the xml file activity_maps.xml is:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<Button
android:id="#+id/send_my_location_btn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Send My location via SMS"/>
<fragment
android:id="#+id/map"
android:name="com.google.android.gms.maps.SupportMapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MapsActivity"/>
</LinearLayout>
If you want to get the whole project, please refer to here.

Android Google Maps v2 ReadWriteDirectByteBuffer Exception

I normally don't get this error but it occurred a few times while loading the map.
Below is my stacktrace and java code
Here's the stacktrace:
E/MAP(23027): java.lang.NullPointerException
E/MAP(23027): at java.nio.ReadWriteDirectByteBuffer.put(ReadWriteDirectByteBuffer.java:137)
E/MAP(23027): at java.nio.ShortToByteBufferAdapter.put(ShortToByteBufferAdapter.java:160)
12-26 17:53:57.519: E/MAP(23027): at com.google.maps.api.android.lib6.gmm6.o.c.a.d.d(Unknown Source)
12-26 17:53:57.519: E/MAP(23027): at com.google.maps.api.android.lib6.gmm6.o.c.a.d.a(Unknown Source)
12-26 17:53:57.519: E/MAP(23027): at com.google.maps.api.android.lib6.gmm6.o.a.a(Unknown Source)12-26 17:53:57.519: E/MAP(23027): at com.google.maps.api.android.lib6.gmm6.o.c.b(Unknown Source)
12-26 17:53:57.519: E/MAP(23027): at com.google.maps.api.android.lib6.gmm6.o.c.a(Unknown Source)
12-26 17:53:57.519: E/MAP(23027): at com.google.maps.api.android.lib6.gmm6.o.l.a(Unknown Source)
12-26 17:53:57.519: E/MAP(23027): at com.google.maps.api.android.lib6.gmm6.o.l.b(Unknown Source)
12-26 17:53:57.519: E/MAP(23027): at com.google.maps.api.android.lib6.gmm6.o.dc.k(Unknown Source)
12-26 17:53:57.519: E/MAP(23027): at com.google.maps.api.android.lib6.gmm6.o.dc.run(Unknown Source)
12-26 17:53:57.531: E/AndroidRuntime(23027): FATAL EXCEPTION: GLThread 4935
12-26 17:53:57.531: E/AndroidRuntime(23027): java.lang.NullPointerException
12-26 17:53:57.531: E/AndroidRuntime(23027): at java.nio.ReadWriteDirectByteBuffer.put(ReadWriteDirectByteBuffer.java:137)
12-26 17:53:57.531: E/AndroidRuntime(23027): at java.nio.ShortToByteBufferAdapter.put(ShortToByteBufferAdapter.java:160)
12-26 17:53:57.531: E/AndroidRuntime(23027): at com.google.maps.api.android.lib6.gmm6.o.c.a.d.d(Unknown Source)
12-26 17:53:57.531: E/AndroidRuntime(23027): at com.google.maps.api.android.lib6.gmm6.o.c.a.d.a(Unknown Source)
12-26 17:53:57.531: E/AndroidRuntime(23027): at com.google.maps.api.android.lib6.gmm6.o.a.a(Unknown Source)
Here is my java code :
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if(isGooglePlay()){
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.activity_start_meter);
// Get handles to the UI view objects
mLatLng = (TextView) findViewById(R.id.lat_lng);
mLatLng.setVisibility(View.GONE);
mAddress = (TextView) findViewById(R.id.address);
mActivityIndicator = (ProgressBar) findViewById(R.id.address_progress);
mConnectionState = (TextView) findViewById(R.id.text_connection_state);
tvStartUpdates = (TextView) findViewById(R.id.start_updates);
tvStopUpdates = (TextView) findViewById(R.id.stop_updates);
showHideCallayout=(LinearLayout) findViewById(R.id.showHideCalLayout);
showHideButlayout=(LinearLayout) findViewById(R.id.showHideButLayout);
btShowHide=(Button) findViewById(R.id.btShowHide);
btShowHide.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
if(btShowHide.getText().toString().equalsIgnoreCase("-")){
showHideButlayout.setVisibility(View.GONE);
showHideCallayout.setVisibility(View.GONE);
btShowHide.setText("+");
}else if(btShowHide.getText().toString().equalsIgnoreCase("+")){
showHideButlayout.setVisibility(View.VISIBLE);
showHideCallayout.setVisibility(View.VISIBLE);
btShowHide.setText("-");
}
}
});
showHideButlayout.setVisibility(View.VISIBLE);
showHideCallayout.setVisibility(View.VISIBLE);
tvStartUpdates.setEnabled(true);
tvStopUpdates.setEnabled(false);
mConnectionState.setVisibility(View.GONE);
mConnectionStatus = (TextView) findViewById(R.id.text_connection_status);
mConnectionStatus.setVisibility(View.GONE);
distancekmm = (TextView) findViewById(R.id.label_lat_lng);
tvTotalFaree = (TextView) findViewById(R.id.tvTotalFareee);
tvBaseFare = (TextView) findViewById(R.id.tvbaseFare);
Toast.makeText(StartMeterActivity.this, "GPS signal not found", Toast.LENGTH_LONG).show();
gps = new GPSTracker(StartMeterActivity.this);
if(gps.canGetLocation()){
mLocationRequest = LocationRequest.create();
mLocationRequest.setInterval(LocationUtils.UPDATE_INTERVAL_IN_MILLISECONDS);
// Use high accuracy
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
// Set the interval ceiling to one minute
mLocationRequest.setFastestInterval(LocationUtils.FAST_INTERVAL_CEILING_IN_MILLISECONDS);
// Note that location updates are off until the user turns them on
mUpdatesRequested = false;
if (mGoogleMap == null) {
SupportMapFragment fm = (SupportMapFragment)getSupportFragmentManager().findFragmentById(R.id.map);
// Getting Map for the SupportMapFragment
mGoogleMap = fm.getMap();
// check if map is created successfully or not
if (mGoogleMap == null) {
Toast.makeText(getApplicationContext(),
"Sorry! unable to create maps", Toast.LENGTH_SHORT)
.show();
}
// while(mGoogleMap==null){
//
// }
// if(mGoogleMap!=null){
mGoogleMap.setMapType(GoogleMap.MAP_TYPE_NORMAL);
//mGoogleMap.setPadding(0, 0, 0, 520);
// Enable MyLocation Button in the Map
mGoogleMap.setMyLocationEnabled(true);
//mGoogleMap.getUiSettings().setZoomControlsEnabled(true);
// LocationManager locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);
//
// // Creating a criteria object to retrieve provider
// Criteria criteria = new Criteria();
//
// // Getting the name of the best provider
// String provider = locationManager.getBestProvider(criteria, true);
//
// // Getting Current Location From GPS
Location l = getLocationn();
LatLng ll=new LatLng(l.getLatitude(), l.getLongitude());
// CameraPosition cameraPosition = new CameraPosition.Builder()
// .target(ll) // Sets the center of the map to Mountain View
// .zoom(14) // Sets the zoom
// //.bearing(90) // Sets the orientation of the camera to east
// // .tilt(30) // Sets the tilt of the camera to 30 degrees
// .build(); // Creates a CameraPosition from the builder
// mGoogleMap.animateCamera(CameraUpdateFactory.newCameraPosition(cameraPosition));
mGoogleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(ll, 16));
//
// Open Shared Preferences
// mPrefs = getSharedPreferences(LocationUtils.SHARED_PREFERENCES, Context.MODE_PRIVATE);
// Get an editor
// mEditor = mPrefs.edit();
/*
* Create a new location client, using the enclosing class to
* handle callbacks.
*/
mLocationClient = new LocationClient(this, this, this); }
} else{
// // can't get location
// // GPS or Network is not enabled
// // Ask user to enable GPS/network in settings
gps.showSettingsAlert();
//
}
}}
private void setRetainInstance(boolean b) {
// TODO Auto-generated method stub
}
/*
* Called when the Activity is no longer visible at all.
* Stop updates and disconnect.
*/
#Override
public void onStop() {
if (mLocationClient.isConnected()) {
mLocationClient.removeLocationUpdates(this);
}
mLocationClient.disconnect();
// If the client is connected
// if (mLocationClient.isConnected()) {
// stopPeriodicUpdates();
// }
//
// // After disconnect() is called, the client is considered "dead".
// mLocationClient.disconnect();
super.onStop();
}
/*
* Called when the Activity is going into the background.
* Parts of the UI may be visible, but the Activity is inactive.
*/
#Override
public void onPause() {
// Save the current setting for updates
// mEditor.putBoolean(LocationUtils.KEY_UPDATES_REQUESTED, mUpdatesRequested);
// mEditor.commit();
super.onPause();
}
/*
* Called when the Activity is restarted, even before it becomes visible.
*/
#Override
public void onStart() {
super.onStart();
/*
* Connect the client. Don't re-start any requests here;
* instead, wait for onResume()
*/
mLocationClient.connect();
mGoogleMap.animateCamera(CameraUpdateFactory.zoomTo(16));
}
/*
* Called when the system detects that this Activity is now visible.
*/
#Override
public void onResume() {
super.onResume();
mLocationClient.connect();
int errorCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);
if(errorCode != ConnectionResult.SUCCESS && GooglePlayServicesUtil.isUserRecoverableError(errorCode)){
Dialog d = GooglePlayServicesUtil.getErrorDialog(errorCode, this, 0);
d.show();
}
// locationManager.requestLocationUpdates(provider, 400, 1, this);
// If the app already has a setting for getting location updates, get it
// if (mPrefs.contains(LocationUtils.KEY_UPDATES_REQUESTED)) {
// mUpdatesRequested = mPrefs.getBoolean(LocationUtils.KEY_UPDATES_REQUESTED, false);
//
// // Otherwise, turn off location updates until requested
// } else {
// mEditor.putBoolean(LocationUtils.KEY_UPDATES_REQUESTED, false);
// mEditor.commit();
// }
}
/*
* Handle results returned to this Activity by other Activities started with
* startActivityForResult(). In particular, the method onConnectionFailed() in
* LocationUpdateRemover and LocationUpdateRequester may call startResolutionForResult() to
* start an Activity that handles Google Play services problems. The result of this
* call returns here, to onActivityResult.
*/
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
// Choose what to do based on the request code
switch (requestCode) {
// If the request code matches the code sent in onConnectionFailed
case LocationUtils.CONNECTION_FAILURE_RESOLUTION_REQUEST :
switch (resultCode) {
// If Google Play services resolved the problem
case Activity.RESULT_OK:
// Log the result
Log.d(LocationUtils.APPTAG, getString(R.string.resolved));
// Display the result
mConnectionState.setText(R.string.connected);
mConnectionStatus.setText(R.string.resolved);
mConnectionStatus.setVisibility(View.GONE);
mConnectionState.setVisibility(View.GONE);
break;
// If any other result was returned by Google Play services
default:
// Log the result
Log.d(LocationUtils.APPTAG, getString(R.string.no_resolution));
// Display the result
mConnectionState.setText(R.string.disconnected);
mConnectionStatus.setText(R.string.no_resolution);
mConnectionStatus.setVisibility(View.GONE);
mConnectionState.setVisibility(View.GONE);
break;
}
// If any other request code was received
default:
// Report that this Activity received an unknown requestCode
Log.d(LocationUtils.APPTAG,
getString(R.string.unknown_activity_request_code, requestCode));
break;
}
}
/**
* Verify that Google Play services is available before making a request.
*
* #return true if Google Play services is available, otherwise false
*/
private boolean servicesConnected() {
// Check that Google Play services is available
int resultCode =
GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);
// If Google Play services is available
if (ConnectionResult.SUCCESS == resultCode) {
// In debug mode, log the status
Log.d(LocationUtils.APPTAG, getString(R.string.play_services_available));
// Continue
return true;
// Google Play services was not available for some reason
} else {
// Display an error dialog
Dialog dialog = GooglePlayServicesUtil.getErrorDialog(resultCode, this, 0);
if (dialog != null) {
ErrorDialogFragment errorFragment = new ErrorDialogFragment();
errorFragment.setDialog(dialog);
errorFragment.show(getSupportFragmentManager(), LocationUtils.APPTAG);
}
return false;
}
}
/**
* Invoked by the "Get Location" button.
*
* Calls getLastLocation() to get the current location
*
* #param v The view object associated with this method, in this case a Button.
*/
public void getLocation(View v) {
// If Google Play Services is available
Intent i=new Intent(getApplicationContext(), WaitingActivity.class);
startActivity(i);
}
}
/**
* Invoked by the "Get Address" button.
* Get the address of the current location, using reverse geocoding. This only works if
* a geocoding service is available.
*
* #param v The view object associated with this method, in this case a Button.
*/
// For Eclipse with ADT, suppress warnings about Geocoder.isPresent()
#SuppressLint("NewApi")
public void getAddress(View v) {
// In Gingerbread and later, use Geocoder.isPresent() to see if a geocoder is available.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD && !Geocoder.isPresent()) {
// No geocoder is present. Issue an error message
Toast.makeText(this, R.string.no_geocoder_available, Toast.LENGTH_LONG).show();
return;
}
if (servicesConnected()) {
// Get the current location
Location currentLocation = mLocationClient.getLastLocation();
// Turn the indefinite activity indicator on
mActivityIndicator.setVisibility(View.VISIBLE);
// Start the background task
(new StartMeterActivity.GetAddressTask(this)).execute(currentLocation);
}
}
/**
* Invoked by the "Start Updates" button
* Sends a request to start location updates
*
* #param v The view object associated with this method, in this case a Button.
*/
public void startUpdates(View v) {
mUpdatesRequested = true;
// tvBaseFare.setVisibility(View.VISIBLE);
// tvTotalFare.setVisibility(View.VISIBLE);
if (servicesConnected()) {
startPeriodicUpdates();
}
}
/**
* Invoked by the "Stop Updates" button
* Sends a request to remove location updates
* request them.
*
* #param v The view object associated with this method, in this case a Button.
*/
public void stopUpdates(View v) {
mUpdatesRequested = false;
if (servicesConnected()) {
stopPeriodicUpdates();
}
}
/*
* Called by Location Services when the request to connect the
* client finishes successfully. At this point, you can
* request the current location or start periodic updates
*/
#Override
public void onConnected(Bundle bundle) {
mConnectionStatus.setText(R.string.connected);
mConnectionStatus.setVisibility(View.GONE);
// prevLocation = getLocation(mLocationClient);
if (mUpdatesRequested) {
startPeriodicUpdates();
}
}
/*
* Called by Location Services if the connection to the
* location client drops because of an error.
*/
#Override
public void onDisconnected() {
mConnectionStatus.setText(R.string.disconnected);
mConnectionStatus.setVisibility(View.GONE);
}
/*
* Called by Location Services if the attempt to
* Location Services fails.
*/
#Override
public void onConnectionFailed(ConnectionResult connectionResult) {
/*
* Google Play services can resolve some errors it detects.
* If the error has a resolution, try sending an Intent to
* start a Google Play services activity that can resolve
* error.
*/
if (connectionResult.hasResolution()) {
try {
// Start an Activity that tries to resolve the error
connectionResult.startResolutionForResult(
this,
LocationUtils.CONNECTION_FAILURE_RESOLUTION_REQUEST);
/*
* Thrown if Google Play services canceled the original
* PendingIntent
*/
} catch (IntentSender.SendIntentException e) {
// Log the error
e.printStackTrace();
}
} else {
// If no resolution is available, display a dialog to the user with the error.
showErrorDialog(connectionResult.getErrorCode());
}
}
/**
* Report location updates to the UI.
*
* #param location The updated location.
*/
#Override
public void onLocationChanged(Location location) {
changedLocation=location;
// LatLng endPosition = new LatLng(changedLocation.getLatitude(), changedLocation.getLongitude());
mConnectionStatus.setText(R.string.location_updated);
// In the UI, set the latitude and longitude to the value received
// if (marker != null) {
// marker.remove();
// }
// Report to the UI that the location was updated
mConnectionStatus.setText(R.string.location_updated);
mConnectionStatus.setVisibility(View.GONE);
mConnectionState.setVisibility(View.GONE);
// In the UI, set the latitude and longitude to the value received
double lat = location.getLatitude();
double lng = location.getLongitude();
Toast.makeText(this, "Location " + lat+","+lng,
1000).show();
LatLng coordinate = new LatLng(lat, lng);
mGoogleMap.moveCamera(CameraUpdateFactory.newLatLng(coordinate));
//mGoogleMap.animateCamera(CameraUpdateFactory.zoomTo(16));
//mLatLng.setText(lat+" "+lng);
// mLatLng.setText(df.format(lat)+" " +df.format(lng));
// Toast.makeText(this, "Location " + coordinate.latitude+","+coordinate.longitude,1000).show();
// mGoogleMap.moveCamera(CameraUpdateFactory.newLatLng(coordinate));
// mGoogleMap.animateCamera(CameraUpdateFactory.zoomTo(17));
rectOptions.add(new LatLng(lat, lng));
this.savePolyline=rectOptions;
mGoogleMap.addPolyline(rectOptions);
}

Categories

Resources