如何在当前纬度,经度上创建地理围栏(创建和监控地理围栏)。 我正在尝试多个例子,但没有创建。 使用此代码:
public Geofence geofence(float radius, double latitude, double longitude) {
String id = UUID.randomUUID().toString();
return new Geofence.Builder()
.setRequestId(id)
.setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER)
.setCircularRegion(latitude, longitude, radius)
.setExpirationDuration(Geofence.NEVER_EXPIRE)
.build();
}
答案 0 :(得分:2)
谷歌的这个教程非常容易理解:
Udacity还有一门课程教授位置服务,包括地理围栏:
https://www.udacity.com/course/google-location-services-on-android--ud876-1
将Google Play服务添加到Gradle文件:
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.android.support:appcompat-v7:22.0.0'
compile 'com.google.android.gms:play-services:7.3.0'
}
添加到清单文件:
<meta-data
android:name="com.google.android.gms.version"
android:value="@integer/google_play_services_version" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
添加到Activity的XML布局文件:
<Button
android:id="@+id/add_geofences_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:onClick="addGeofencesButtonHandler"
android:text="Add GeoFences" />
添加到Activity的Java文件:
public class MainActivity extends Activity
implements
GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener,
ResultCallback<Status>{
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mAddGeofencesButton = (Button) findViewById(R.id.add_geofences_button);
// Empty list for storing geofences.
mGeofenceList = new ArrayList<Geofence>();
// Get the geofences used. Geofence data is hard coded in this sample.
populateGeofenceList();
// Kick off the request to build GoogleApiClient.
buildGoogleApiClient();
}
protected synchronized void buildGoogleApiClient() {
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
}
public void populateGeofenceList() {
for (Map.Entry<String, LatLng> entry : Constants.LANDMARKS.entrySet()) {
mGeofenceList.add(new Geofence.Builder()
.setRequestId(entry.getKey())
.setCircularRegion(
entry.getValue().latitude,
entry.getValue().longitude,
Constants.GEOFENCE_RADIUS_IN_METERS
)
.setExpirationDuration(Constants.GEOFENCE_EXPIRATION_IN_MILLISECONDS)
.setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER |
Geofence.GEOFENCE_TRANSITION_EXIT)
.build());
}
}
@Override
protected void onStart() {
super.onStart();
if (!mGoogleApiClient.isConnecting() || !mGoogleApiClient.isConnected()) {
mGoogleApiClient.connect();
}
}
@Override
protected void onStop() {
super.onStop();
if (mGoogleApiClient.isConnecting() || mGoogleApiClient.isConnected()) {
mGoogleApiClient.disconnect();
}
}
@Override
public void onConnected(Bundle connectionHint) {
}
@Override
public void onConnectionFailed(ConnectionResult result) {
// Do something with result.getErrorCode());
}
@Override
public void onConnectionSuspended(int cause) {
mGoogleApiClient.connect();
}
public void addGeofencesButtonHandler(View view) {
if (!mGoogleApiClient.isConnected()) {
Toast.makeText(this, "Google API Client not connected!", Toast.LENGTH_SHORT).show();
return;
}
try {
LocationServices.GeofencingApi.addGeofences(
mGoogleApiClient,
getGeofencingRequest(),
getGeofencePendingIntent()
).setResultCallback(this); // Result processed in onResult().
} catch (SecurityException securityException) {
// Catch exception generated if the app does not use ACCESS_FINE_LOCATION permission.
}
}
private GeofencingRequest getGeofencingRequest() {
GeofencingRequest.Builder builder = new GeofencingRequest.Builder();
builder.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER);
builder.addGeofences(mGeofenceList);
return builder.build();
}
private PendingIntent getGeofencePendingIntent() {
Intent intent = new Intent(this, GeofenceTransitionsIntentService.class);
// We use FLAG_UPDATE_CURRENT so that we get the same pending intent back when calling addgeoFences()
return PendingIntent.getService(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
}
public void onResult(Status status) {
if (status.isSuccess()) {
Toast.makeText(
this,
"Geofences Added",
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());
}
}
创建一个名为Constans的java文件:
public class Constants {
public static final long GEOFENCE_EXPIRATION_IN_MILLISECONDS = 12 * 60 * 60 * 1000;
public static final float GEOFENCE_RADIUS_IN_METERS = 20;
public static final HashMap<String, LatLng> LANDMARKS = new HashMap<String, LatLng>();
static {
// San Francisco International Airport.
LANDMARKS.put("Moscone South", new LatLng(37.783888,-122.4009012));
// Googleplex.
LANDMARKS.put("Japantown", new LatLng(37.785281,-122.4296384));
// Test
LANDMARKS.put("SFO", new LatLng(37.621313,-122.378955));
}
}
创建一个名为GeofenceTransitionsIntentService的java文件:
public class GeofenceTransitionsIntentService extends IntentService {
protected static final String TAG = "GeofenceTransitionsIS";
public GeofenceTransitionsIntentService() {
super(TAG); // use TAG to name the IntentService worker thread
}
@Override
protected void onHandleIntent(Intent intent) {
GeofencingEvent event = GeofencingEvent.fromIntent(intent);
if (event.hasError()) {
Log.e(TAG, "GeofencingEvent Error: " + event.getErrorCode());
return;
}
}
String description = getGeofenceTransitionDetails(event);
sendNotification(description);
}
private static String getGeofenceTransitionDetails(GeofencingEvent event) {
String transitionString =
GeofenceStatusCodes.getStatusCodeString(event.getGeofenceTransition());
List triggeringIDs = new ArrayList();
for (Geofence geofence : event.getTriggeringGeofences()) {
triggeringIDs.add(geofence.getRequestId());
}
return String.format("%s: %s", transitionString, TextUtils.join(", ", triggeringIDs));
}
private void sendNotification(String notificationDetails) {
// Create an explicit content Intent that starts MainActivity.
Intent notificationIntent = new Intent(getApplicationContext(), MainActivity.class);
// Get a PendingIntent containing the entire back stack.
TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
stackBuilder.addParentStack(MainActivity.class).addNextIntent(notificationIntent);
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.setColor(Color.RED)
.setContentTitle(notificationDetails)
.setContentText("Click notification to return to App")
.setContentIntent(notificationPendingIntent)
.setAutoCancel(true);
// Fire and notify the built Notification.
NotificationManager notificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(0, builder.build());
}
您应该坚持使用他们的教程,而不是将代码复制并粘贴到项目中:D
答案 1 :(得分:0)
我在服务中这样做
<强> GeolocationService 强>
public class GeolocationService extends Service implements LocationListener,
GoogleApiClient.OnConnectionFailedListener, GoogleApiClient.ConnectionCallbacks {
private Context mContext;
private GoogleApiClient mGoogleApiClient;
private LocationRequest mLocationRequest;
// private Location mLastLocation;
private PendingIntent mGeofencePendingIntent;
private String mLastUpdateTime;
public static boolean isGeoFenceAdded = false;
private boolean mUpdateGeoFence = false;
private boolean mRemoveAllGeoFence = false;
private static final long TIME_OUT = 100;
@Override
public void onCreate() {
super.onCreate();
mContext = GeolocationService.this;
buildGoogleApiClient();
createLocationRequest();
}
protected synchronized void buildGoogleApiClient() {
mGoogleApiClient = new GoogleApiClient.Builder(mContext)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
/// FIXME: 2/15/2017 connect should be handled through onStart and onStop of Activity
mGoogleApiClient.connect();
}
protected void createLocationRequest() {
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(5000);//set the interval in which you want to get locations
mLocationRequest.setFastestInterval(2500);//if a location is available sooner you can get it (i.e. another app is using the location services)
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (intent != null) {
if (intent.getAction() != null) {
if (intent.getAction().equals(Constants.ACTION_UPDATE_GEOFENCE)) {
//// FIXME: 3/21/2017 you can also receive triggered location here..
mUpdateGeoFence = true;
isGeoFenceAdded = false;
mRemoveAllGeoFence = false;
} else if (intent.getAction().equals(Constants.ACTION_ADD_GEOFENCE)) {
mUpdateGeoFence = false;
isGeoFenceAdded = false;
mRemoveAllGeoFence = false;
} else if (intent.getAction().equals(Constants.ACTION_REMOVE_ALL_GEOFENCE)) {
mRemoveAllGeoFence = true;
isGeoFenceAdded = true;
mUpdateGeoFence = false;
}
}
}
//try this for null as http://stackoverflow.com/a/25096022/3496570
///return START_REDELIVER_INTENT;
return super.onStartCommand(intent, flags, startId);
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onConnected(@Nullable Bundle bundle) {
startLocationUpdates(mContext);
}
@Override
public void onConnectionSuspended(int i) {
switch (i) {
case CAUSE_SERVICE_DISCONNECTED:
/*if (onLocationUpdateListener != null)
onLocationUpdateListener.onError(
Constants.ErrorType.SERVICE_DISCONNECTED);*/
break;
case CAUSE_NETWORK_LOST:
/*if (onLocationUpdateListener != null)
onLocationUpdateListener.onError(
Constants.ErrorType.NETWORK_LOST);*/
break;
}
//// FIXME: 3/2/2017 check is it right to check for re Connecting..
//--- http://stackoverflow.com/a/27350444/3496570
///mGoogleApiClient.connect();
}
@Override
public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
/*if (onLocationUpdateListener != null)
onLocationUpdateListener.onError(
Constants.ErrorType.CONNECTION_FAIL);*/
//// FIXME: 3/3/2017 call a transparent activity and call startResolutionForresult from their and return result to service using action
if (connectionResult.hasResolution()) {
/*try {
// !!!
connectionResult.startResolutionForResult(this, REQUEST_CODE_RESOLVE_ERR);
} catch (IntentSender.SendIntentException e) {
e.printStackTrace();
}*/
} else {
/*GoogleApiAvailability.getInstance().getErrorDialog(mContext, connectionResult.getErrorCode(), 0).show();
return;*/
}
}
@Override
public void onLocationChanged(final Location currentLocation) {
setupGeoFencePoints(currentLocation);
/*if (onLocationUpdateListener != null && mLocation != null) {
onLocationUpdateListener.onLocationChange(mLocation);
}*/
}
private void setupGeoFencePoints(final Location currentLocation) {
mLastUpdateTime = DateFormat.getTimeInstance().format(new Date());
// mLastLocation = currentLocation;
if (currentLocation != null && isGeoFenceAdded == false)
{
if (mUpdateGeoFence) {
if (mGoogleApiClient != null && mGoogleApiClient.isConnected()) {
LocationServices.GeofencingApi.removeGeofences(mGoogleApiClient
, getGeofencePendingIntent()).setResultCallback(new ResultCallback<Status>() {
@Override
public void onResult(@NonNull Status status) {
if (status.isSuccess()) {
//if old geoFence's remove successfully then add new ones.
addGeoFences(currentLocation);
}
}
});
}
} else {
addGeoFences(currentLocation);
}
}
else if(isGeoFenceAdded && mRemoveAllGeoFence ){
if (mGoogleApiClient != null && mGoogleApiClient.isConnected())
{
LocationServices.GeofencingApi.removeGeofences(mGoogleApiClient
, mGeofencePendingIntent).setResultCallback(new ResultCallback<Status>() {
@Override
public void onResult(@NonNull Status status) {
if (status.isSuccess()) {
mRemoveAllGeoFence = false;
isGeoFenceAdded = false;
//if old geoFence's remove successfully then do nothing.
stopLocationUpdate();
if (mGoogleApiClient != null && mGoogleApiClient.isConnected())
mGoogleApiClient.disconnect();
}
}
});
}
}
}
@Override
public void onDestroy() {
super.onDestroy();
stopLocationUpdate();
if (mGoogleApiClient != null && mGoogleApiClient.isConnected())
mGoogleApiClient.disconnect();
}
private void startLocationUpdates(final Context mContext) {
if (ActivityCompat.checkSelfPermission(mContext,
Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED
&& ActivityCompat.checkSelfPermission(mContext,
Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return;
}
// mLastLocation = FusedLocationApi.getLastLocation(mGoogleApiClient);
PendingResult<Status> pendingResult = FusedLocationApi.requestLocationUpdates(
mGoogleApiClient, mLocationRequest, this);
pendingResult.setResultCallback(new ResultCallback<Status>() {
@Override
public void onResult(@NonNull Status status) {
//update it's code too.
if (status.isSuccess()) {
Toast.makeText(mContext, "location Update Started",
Toast.LENGTH_SHORT).show();
} else if (status.hasResolution()) {
Toast.makeText(mContext, "Open intent to resolve",
Toast.LENGTH_SHORT).show();
}
}
});
}
private void stopLocationUpdate() {
//three types of constructor ..
if (mGoogleApiClient != null && mGoogleApiClient.isConnected()) {
FusedLocationApi.removeLocationUpdates(
mGoogleApiClient, this);
}
}
public void addGeoFences(Location currentLocation) {
if (mGoogleApiClient != null && mGoogleApiClient.isConnected()) {
try {
if (getGeofencingRequest(currentLocation) != null) {
LocationServices.GeofencingApi.addGeofences(
mGoogleApiClient,
// The GeofenceRequest object.
getGeofencingRequest(currentLocation),
// 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()
//).await(TimeOut,TimeUnit.Miilisecponds);
).setResultCallback(new ResultCallback<Status>() {
@Override
public void onResult(@NonNull Status status) {
if (status.isSuccess()) {
Toast.makeText(mContext, "Geo Fence Added", Toast.LENGTH_SHORT).show();
isGeoFenceAdded = true;
mRemoveAllGeoFence = false;
mUpdateGeoFence = false;
/// FIXME: 3/2/2017 I didn't have to draw it.
///broadcastDrawGeoFenceOnMap();
} else {
String errorMessage = getErrorString(mContext, status.getStatusCode());
Toast.makeText(mContext, "Status Failed", Toast.LENGTH_SHORT).show();
}
}
}); // Result processed in onResult().
}
} catch (SecurityException securityException) {
securityException.printStackTrace();
// Catch exception generated if the app does not use ACCESS_FINE_LOCATION permission.
//logSecurityException(securityException);
}
}
}
private PendingIntent getGeofencePendingIntent() {
if (mGeofencePendingIntent != null) {
return mGeofencePendingIntent;
}
// Reuse the PendingIntent if we already have it.
/// FIXME: 2/9/2017 Update the below class with a receiever..
Intent intent = new Intent(mContext, GeofenceReceiver.class);///GeofenceTransitionsIntentService.class);
// We use FLAG_UPDATE_CURRENT so that we get the same pending intent back when calling
// addGeofences() and removeGeofences().
/// FIXME: 3/1/2017 It must be reciever not IntentService
mGeofencePendingIntent = PendingIntent.getBroadcast(mContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
return mGeofencePendingIntent;
}
private GeofencingRequest getGeofencingRequest(Location mCurrentLocation) {
/// FIXME: 2/13/2017 mLastLocation can be null because it will take time for the first time.
/// this request should be called after first mLastLocation has been fetched..
GeofencingRequest geofencingRequest = null;
if (mCurrentLocation != null) {
List<SimpleGeofence> simpleFenceList = SimpleGeofenceStore
.getInstance().getLatestGeoFences(mCurrentLocation);
simpleFenceList.add(new SimpleGeofence("currentLocation",
mCurrentLocation.getLatitude(), mCurrentLocation.getLongitude(),
100f, GEOFENCE_EXPIRATION_IN_MILLISECONDS,
Geofence.GEOFENCE_TRANSITION_EXIT));
ListSharedPref.saveAnyTypeOfList(ListSharedPref.GEO_FENCE_LIST_KEY, simpleFenceList);
GeofencingRequest.Builder geofencingRequestBuilder = new GeofencingRequest.Builder();
geofencingRequestBuilder.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER);
for (SimpleGeofence simpleGeofence : simpleFenceList)
geofencingRequestBuilder.addGeofence(simpleGeofence.toGeofence());
geofencingRequest = geofencingRequestBuilder.build();
}
// Return a GeofencingRequest.
return geofencingRequest;
}
}
<强> GeofenceReceiver 强>
public class GeofenceReceiver extends IntentService {
public static final int NOTIFICATION_ID = 1;
public GeofenceReceiver() {
super("GeofenceReceiver");
}
@Override
protected void onHandleIntent(Intent intent) {
GeofencingEvent geoEvent = GeofencingEvent.fromIntent(intent);
Location triggredLocation = geoEvent.getTriggeringLocation();
if (geoEvent.hasError()) {
Log.d(HomeActivity.TAG, "Error GeofenceReceiver.onHandleIntent");
} else {
Log.d(HomeActivity.TAG, "GeofenceReceiver : Transition -> "
+ geoEvent.getGeofenceTransition());
int transitionType = geoEvent.getGeofenceTransition();
if (transitionType == Geofence.GEOFENCE_TRANSITION_ENTER
|| transitionType == Geofence.GEOFENCE_TRANSITION_DWELL
|| transitionType == Geofence.GEOFENCE_TRANSITION_EXIT) {
List<Geofence> triggerList = geoEvent.getTriggeringGeofences();
//if(triggerList.g)
Type listType = new TypeToken<ArrayList<SimpleGeofence>>(){}.getType();
List<SimpleGeofence> geoFenceList = GenericPref.readAnyTypeOfList(GenericPref.GEO_FENCE_LIST_KEY,listType);
for (Geofence geofence : triggerList)
{
/*SimpleGeofence sg = SimpleGeofenceStore.getInstance()
.getSimpleGeofences().get(geofence.getRequestId());*/
SimpleGeofence sg = null;
for(SimpleGeofence simpleGeofence : geoFenceList){
if(simpleGeofence.getId().equalsIgnoreCase(geofence.getRequestId())){
sg = simpleGeofence;
break;
}
}
String transitionName = "";
switch (transitionType) {
case Geofence.GEOFENCE_TRANSITION_DWELL:
transitionName = "dwell";
break;
case Geofence.GEOFENCE_TRANSITION_ENTER:
transitionName = "enter";
String date = DateFormat.format("yyyy-MM-dd hh:mm:ss",
new Date()).toString();
EventDataSource eds = new EventDataSource(
getApplicationContext());
eds.create(transitionName, date, geofence.getRequestId());
eds.close();
GeofenceNotification geofenceNotification = new GeofenceNotification(
this);
if(sg != null){
geofenceNotification
.displayNotification(sg, transitionType);
}
break;
case Geofence.GEOFENCE_TRANSITION_EXIT:
transitionName = "exit";
broadcastUpdateGeoFences();
//update your List
// Unregister all geoFences and reRegister it again
break;
}
}
}
}
}
public void broadcastUpdateGeoFences() {
//// FIXME: 3/2/2017 what if app is closed
HomeActivity.geofencesAlreadyRegistered = false;
MainActivity.isGeoFenceAdded = false;
Intent intent = new Intent(Constants.RECEIVER_GEOFENCE);
intent.putExtra("done", 1);
sendBroadcast(intent);
}
}
答案 2 :(得分:0)
我的要求是,当我单击地图时,然后在该位置创建地理围栏圈。并在我们当前位置进入该围栏和从该围栏退出时显示通知。
MapsActivity.java
import android.Manifest;
import android.annotation.SuppressLint;
import android.app.AlertDialog;
import android.app.PendingIntent;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Color;
import android.location.Location;
import com.google.android.gms.common.api.ResultCallback;
import com.google.android.gms.common.api.Status;
import com.google.android.gms.location.Geofence;
import com.google.android.gms.location.GeofencingRequest;
import com.google.android.gms.location.LocationListener;
import android.os.Build;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v4.app.FragmentActivity;
import android.os.Bundle;
import android.support.v4.content.ContextCompat;
import android.util.Log;
import android.view.MenuItem;
import android.widget.Toast;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationServices;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.OnMapReadyCallback;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.BitmapDescriptorFactory;
import com.google.android.gms.maps.model.Circle;
import com.google.android.gms.maps.model.CircleOptions;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.MarkerOptions;
public class MapsActivity extends FragmentActivity implements OnMapReadyCallback,
GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener,
LocationListener,
GoogleMap.OnMapClickListener, ResultCallback<Status> {
private GoogleMap mMap;
SupportMapFragment mapFragment;
LocationRequest mLocationRequest;
GoogleApiClient mGoogleApiClient;
Location mLastLocation;
Marker mCurrLocationMarker;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_maps);
// Obtain the SupportMapFragment and get notified when the map is ready to be used.
mapFragment = (SupportMapFragment) getSupportFragmentManager()
.findFragmentById(R.id.map);
mapFragment.getMapAsync(this);
}
/**
* Manipulates the map once available.
* This callback is triggered when the map is ready to be used.
* This is where we can add markers or lines, add listeners or move the camera. In this case,
* we just add a marker near Sydney, Australia.
* If Google Play services is not installed on the device, the user will be prompted to install
* it inside the SupportMapFragment. This method will only be triggered once the user has
* installed Google Play services and returned to the app.
*/
@Override
public void onMapReady(GoogleMap googleMap) {
mMap = googleMap;
mMap.setMapType(GoogleMap.MAP_TYPE_HYBRID);
mMap.setOnMapClickListener(this);
//Initialize Google Play Services
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (ContextCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED) {
//Location Permission already granted
buildGoogleApiClient();
mMap.setMyLocationEnabled(true);
} else {
//Request Location Permission
checkLocationPermission();
}
} else {
buildGoogleApiClient();
mMap.setMyLocationEnabled(true);
}
}
protected synchronized void buildGoogleApiClient() {
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
mGoogleApiClient.connect();
}
@Override
public void onConnected(Bundle bundle) {
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(1000);
mLocationRequest.setFastestInterval(1000);
mLocationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
if (ContextCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED) {
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);
}
}
@Override
public void onConnectionSuspended(int i) {
}
@Override
public void onLocationChanged(Location location) {
mLastLocation = location;
if (mCurrLocationMarker != null) {
mCurrLocationMarker.remove();
}
//Place current location marker
LatLng latLng = new LatLng(location.getLatitude(), location.getLongitude());
MarkerOptions markerOptions = new MarkerOptions();
markerOptions.position(latLng);
markerOptions.title("Current Position");
markerOptions.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_MAGENTA));
mCurrLocationMarker = mMap.addMarker(markerOptions);
//move map camera
mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(latLng, 15));
Location targetLocation = new Location("");//provider name is unnecessary
targetLocation.setLatitude(18.569557d);//your coords of course
targetLocation.setLongitude(73.879369d);
// This is also working
/* if (location.distanceTo(targetLocation) < 100) {
// bingo!
Toast.makeText(this, "You are at MplusSoft Technology", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(this, "You are not at your place.", Toast.LENGTH_SHORT).show();
}*/
}
public static final int MY_PERMISSIONS_REQUEST_LOCATION = 99;
private void checkLocationPermission() {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
// Should we show an explanation?
if (ActivityCompat.shouldShowRequestPermissionRationale(this,
Manifest.permission.ACCESS_FINE_LOCATION)) {
// Show an explanation to the user *asynchronously* -- don't block
// this thread waiting for the user's response! After the user
// sees the explanation, try again to request the permission.
new AlertDialog.Builder(this)
.setTitle("Location Permission Needed")
.setMessage("This app needs the Location permission, please accept to use location functionality")
.setPositiveButton("OK", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
//Prompt the user once explanation has been shown
ActivityCompat.requestPermissions(MapsActivity.this,
new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
MY_PERMISSIONS_REQUEST_LOCATION);
}
})
.create()
.show();
} else {
// No explanation needed, we can request the permission.
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
MY_PERMISSIONS_REQUEST_LOCATION);
}
}
}
@Override
public void onRequestPermissionsResult(int requestCode,
String permissions[], int[] grantResults) {
switch (requestCode) {
case MY_PERMISSIONS_REQUEST_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
// location-related task you need to do.
if (ContextCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED) {
if (mGoogleApiClient == null) {
buildGoogleApiClient();
}
mMap.setMyLocationEnabled(true);
}
} else {
// permission denied, boo! Disable the
// functionality that depends on this permission.
Toast.makeText(this, "permission denied", Toast.LENGTH_LONG).show();
}
return;
}
// other 'case' lines to check for other
// permissions this app might request
}
}
@Override
public void onPause() {
super.onPause();
//stop location updates when Activity is no longer active
if (mGoogleApiClient != null) {
LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, (com.google.android.gms.location.LocationListener) this);
}
}
@Override
public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
}
//------------------------------------- Geo fencing -------------------------------------
@Override
protected void onResume() {
super.onResume();
}
@Override
public void onResult(@NonNull Status status) {
Log.e("onResult: ", "onResult: " + status);
if (status.isSuccess()) {
drawGeofence();
} else {
// inform about fail
}
}
@Override
public void onMapClick(LatLng latLng) {
markerForGeofence(latLng);
}
private Marker geoFenceMarker;
// Create a marker for the geofence creation
private void markerForGeofence(LatLng latLng) {
Log.e("markerForGeofence", "markerForGeofence(" + latLng + ")");
String title = latLng.latitude + ", " + latLng.longitude;
// Define marker options
MarkerOptions markerOptions = new MarkerOptions()
.position(latLng)
.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_ORANGE))
.title(title);
if (mMap != null) {
// Remove last geoFenceMarker
if (geoFenceMarker != null)
geoFenceMarker.remove();
geoFenceMarker = mMap.addMarker(markerOptions);
startGeofence();
}
}
private static final long GEO_DURATION = 60 * 60 * 1000;
private static final String GEOFENCE_REQ_ID = "My Geofence";
private static final float GEOFENCE_RADIUS = 50.0f; // in meters
// Create a Geofence
private Geofence createGeofence(LatLng latLng, float radius) {
Log.e("createGeofence", "createGeofence");
return new Geofence.Builder()
.setRequestId(GEOFENCE_REQ_ID)
.setCircularRegion(latLng.latitude, latLng.longitude, radius)
.setExpirationDuration(GEO_DURATION)
.setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER
| Geofence.GEOFENCE_TRANSITION_EXIT)
.build();
}
// Create a Geofence Request
private GeofencingRequest createGeofenceRequest(Geofence geofence) {
Log.e("createGeofenceRequest", "createGeofenceRequest");
return new GeofencingRequest.Builder()
.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER)
.addGeofence(geofence)
.build();
}
private PendingIntent geoFencePendingIntent;
private final int GEOFENCE_REQ_CODE = 0;
@SuppressLint("LongLogTag")
private PendingIntent createGeofencePendingIntent() {
Log.e("createGeofencePendingIntent", "createGeofencePendingIntent");
if (geoFencePendingIntent != null)
return geoFencePendingIntent;
Intent intent = new Intent(this, GeofenceTrasitionService.class);
return PendingIntent.getService(
this, GEOFENCE_REQ_CODE, intent, PendingIntent.FLAG_UPDATE_CURRENT);
}
// Add the created GeofenceRequest to the device's monitoring list
private void addGeofence(GeofencingRequest request) {
Log.e("addGeofence", "addGeofence");
//if (checkPermission())
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
// TODO: Consider calling
// ActivityCompat#requestPermissions
// here to request the missing permissions, and then overriding
// public void onRequestPermissionsResult(int requestCode, String[] permissions,
// int[] grantResults)
// to handle the case where the user grants the permission. See the documentation
// for ActivityCompat#requestPermissions for more details.
return;
}
LocationServices.GeofencingApi.addGeofences(
mGoogleApiClient,
request,
createGeofencePendingIntent()
).setResultCallback(this);
}
// Draw Geofence circle on GoogleMap
private Circle geoFenceLimits;
private void drawGeofence() {
Log.e("drawGeofence()", "drawGeofence()");
if ( geoFenceLimits != null )
geoFenceLimits.remove();
CircleOptions circleOptions = new CircleOptions()
.center( geoFenceMarker.getPosition())
.strokeColor(Color.argb(50, 70,70,70))
.fillColor( Color.argb(100, 150,150,150) )
.radius( GEOFENCE_RADIUS );
geoFenceLimits = mMap.addCircle( circleOptions );
}
// Start Geofence creation process
private void startGeofence() {
Log.e("startGeofence", "startGeofence()");
if( geoFenceMarker != null ) {
Geofence geofence = createGeofence( geoFenceMarker.getPosition(), GEOFENCE_RADIUS );
GeofencingRequest geofenceRequest = createGeofenceRequest( geofence );
addGeofence( geofenceRequest );
} else {
Log.e("Geofence marker is null", "Geofence marker is null");
}
}
static Intent makeNotificationIntent(Context geofenceService, String msg)
{
Log.e("makeNotificationIntent ",msg);
return new Intent(geofenceService,MainActivity.class);
}
}
GeofenceTrasitionService.java
import android.app.IntentService;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.TaskStackBuilder;
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.support.v4.app.NotificationCompat;
import android.text.TextUtils;
import android.util.Log;
import com.google.android.gms.location.Geofence;
import com.google.android.gms.location.GeofenceStatusCodes;
import com.google.android.gms.location.GeofencingEvent;
import java.util.ArrayList;
import java.util.List;
public class GeofenceTrasitionService extends IntentService {
private static final String TAG = GeofenceTrasitionService.class.getSimpleName();
public static final int GEOFENCE_NOTIFICATION_ID = 0;
public GeofenceTrasitionService() {
super(TAG);
}
@Override
protected void onHandleIntent(Intent intent) {
// Retrieve the Geofencing intent
GeofencingEvent geofencingEvent = GeofencingEvent.fromIntent(intent);
// Handling errors
if ( geofencingEvent.hasError() ) {
String errorMsg = getErrorString(geofencingEvent.getErrorCode() );
Log.e( TAG, errorMsg );
return;
}
// Retrieve GeofenceTrasition
int geoFenceTransition = geofencingEvent.getGeofenceTransition();
// Check if the transition type
if ( geoFenceTransition == Geofence.GEOFENCE_TRANSITION_ENTER ||
geoFenceTransition == Geofence.GEOFENCE_TRANSITION_EXIT ) {
// Get the geofence that were triggered
List<Geofence> triggeringGeofences = geofencingEvent.getTriggeringGeofences();
// Create a detail message with Geofences received
String geofenceTransitionDetails = getGeofenceTrasitionDetails(geoFenceTransition, triggeringGeofences );
// Send notification details as a String
sendNotification( geofenceTransitionDetails );
}
}
// Create a detail message with Geofences received
private String getGeofenceTrasitionDetails(int geoFenceTransition, List<Geofence> triggeringGeofences) {
// get the ID of each geofence triggered
ArrayList<String> triggeringGeofencesList = new ArrayList<>();
for ( Geofence geofence : triggeringGeofences ) {
triggeringGeofencesList.add( geofence.getRequestId() );
}
String status = null;
if ( geoFenceTransition == Geofence.GEOFENCE_TRANSITION_ENTER )
status = "Entering ";
else if ( geoFenceTransition == Geofence.GEOFENCE_TRANSITION_EXIT )
status = "Exiting ";
return status + TextUtils.join( ", ", triggeringGeofencesList);
}
// Send a notification
private void sendNotification( String msg ) {
Log.i(TAG, "sendNotification: " + msg );
// Intent to start the main Activity
Intent notificationIntent = MapsActivity.makeNotificationIntent(
getApplicationContext(), msg
);
TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
stackBuilder.addParentStack(MapsActivity.class);
stackBuilder.addNextIntent(notificationIntent);
PendingIntent notificationPendingIntent = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
// Creating and sending Notification
NotificationManager notificatioMng =
(NotificationManager) getSystemService( Context.NOTIFICATION_SERVICE );
notificatioMng.notify(
GEOFENCE_NOTIFICATION_ID,
createNotification(msg, notificationPendingIntent));
}
// Create a notification
private Notification createNotification(String msg, PendingIntent notificationPendingIntent) {
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this);
notificationBuilder
.setSmallIcon(R.drawable.ic_launcher_background)
.setColor(Color.RED)
.setContentTitle(msg)
.setContentText("Geofence Notification!")
.setContentIntent(notificationPendingIntent)
.setDefaults(Notification.DEFAULT_LIGHTS | Notification.DEFAULT_VIBRATE | Notification.DEFAULT_SOUND)
.setAutoCancel(true);
return notificationBuilder.build();
}
// Handle errors
private static String getErrorString(int errorCode) {
switch (errorCode) {
case GeofenceStatusCodes.GEOFENCE_NOT_AVAILABLE:
return "GeoFence not available";
case GeofenceStatusCodes.GEOFENCE_TOO_MANY_GEOFENCES:
return "Too many GeoFences";
case GeofenceStatusCodes.GEOFENCE_TOO_MANY_PENDING_INTENTS:
return "Too many pending intents";
default:
return "Unknown error.";
}
}
}
activity_maps.xml
<?xml version="1.0" encoding="utf-8"?>
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:map="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
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" />
清单
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="@string/google_maps_key" />
<activity
android:name=".MapsActivity"
android:label="@string/title_activity_maps"> <intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter></activity>
<service android:name=".GeofenceTrasitionService"/>
build.gradle
implementation 'com.android.support:appcompat-v7:28.0.0-rc01'
implementation 'com.google.android.gms:play-services-maps:15.0.1'
implementation 'com.google.android.gms:play-services-location:15.0.1'