Как создать геозону на Android?

Как создать геозону (создание и мониторинг геозон) на текущей широте, долготе. Я пробую несколько примеров, но не создаю. Используя этот код:

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

person RAKESH DADHICH    schedule 06.05.2016    source источник


Ответы (3)


Вот этот учебник от Google, которому очень легко следовать:

http://io2015codelabs.appspot.com/codelabs/geofences

В 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"/>

Добавьте в 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" />

Добавьте в файл 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());
        }
    }

Создайте java-файл с именем Constans:

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

Создайте java-файл с именем GeofenceTransitionsIntentService:

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

Источник

person Marcola Carr    schedule 25.05.2016
comment
В onResult предполагается, что @Override вверху? И я перехожу к красному тексту в GeofenceErrorMessages в GeofenceErrorMessages.getErrorString(this, status.getStatusCode());. Я не могу найти класс GeoFenceErrorMessages - person TheQ; 24.09.2016
comment
Привет, @Override необходим, потому что он будет переопределять реализацию метода onResult по умолчанию. Класс GeoFenceErrorMessages — это пользовательский класс, созданный для получения идентификатора ошибки геозоны и возврата сообщения об ошибке. Эта часть не является необходимой для работы геозоны, но это хорошая практика, дополнительную информацию можно найти в этом курсе на Udacity. : udacity.com/course/google-location- службы-на-андроиде – ud876-1 - person Marcola Carr; 25.09.2016
comment
@MarcolaCarr нам нужно объявить GeofenceTransitionsIntentService в файле манифеста под тегом приложения? - person xaif; 25.10.2019

Я делаю это в сервисе

Служба геолокации

    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;
    }
}

Приемник Geofence

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);
    }
}
person AndroidGeek    schedule 03.05.2017

Мое требование заключалось в том, что когда я нажимаю на карту, то в этом месте я создаю круг геозоны. и показ уведомления, когда наше текущее местоположение входит в этот забор и когда выходит из него.

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'
person Pratibha Sarode    schedule 22.08.2018