地理围栏设置/配置应从活动类完成还是使用服务类完成?

时间:2019-06-06 23:47:36

标签: android geolocation android-pendingintent geofencing android-geofence

我浏览了android的地理围栏文档以及网络上的其他一些示例。它们的共同点是从活动初始化Geofencing客户端,然后添加geofence并在活动本身上分配挂起的意图。在挂起的Intent中,它们通过Intent服务类或Broadcast接收器类。我的第一个问题

  1. 如果我在活动中初始化一个类,说“ GeofenceActivity”,然后关闭该应用程序(按返回按​​钮,还将其从最近使用的应用程序中删除),传入的Intent服务或Broadcast接收器类是否会待定意图仍将能够获取Enter和存在的事件通知?

  2. 我可以初始化服务类中的类,并准备该类中的未决意图吗?

我需要的是,我要设置环境的方式是,即使应用程序无法运行(通过应用程序我的意思是UI,服务也将运行),我仍希望收到有关地理围栏事件的通知。

Service class:
package com.services;


import android.Manifest;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.TaskStackBuilder;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Color;
import android.location.Address;
import android.location.Geocoder;
import android.location.Location;
import android.media.MediaPlayer;
import android.os.CountDownTimer;
import android.os.Handler;
import android.os.Looper;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v4.app.JobIntentService;
import android.support.v4.app.NotificationCompat;
import android.support.v4.content.LocalBroadcastManager;
import android.text.TextUtils;
import android.util.Log;
import android.widget.Toast;

import com.google.android.gms.location.Geofence;
import com.google.android.gms.location.GeofenceStatusCodes;
import com.google.android.gms.location.GeofencingClient;
import com.google.android.gms.location.GeofencingEvent;
import com.google.android.gms.location.GeofencingRequest;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationServices;
import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.Task;
import receiver.GeofenceBroadcastReceiver;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Locale;

public class GeofenceTransitionsJobIntentService extends JobIntentService {

    static MediaPlayer mp;

    private static final String GEO_PENDING_KEY = "MMW-GEOFENCING-KEY";
    private static PendingIntent mGeofencePendingIntent;
    private static LocationRequest mLocationRequest;
    public static GeofencingClient GEOFENCING_CLIENT;
    private static Context geocontext;
    private static CountDownTimer timer;
    private static double latitude, longitude;
    private static float radius;
    private static ArrayList<Geofence> mGeofenceList;

    private static final String IDENTIFIER = "LocationAlertIS";
    int geofenceTransition;
    private static final int JOB_ID = 573;
    //private static final String TAG = "GeofenceTransitionsIS";
    private static final String TAG = "Ganesh";
    private static final String CHANNEL_ID = "channel_01";

    @Override
    public void onCreate() {
        super.onCreate();
        Log.i(TAG, "onCreate: GEO FENCING STARTED");
        SetTimerStatus(true);
        PrepareGeoClient();
    }

    @Override
    public void onDestroy() {
        Log.i(TAG, "onDestroy: GEO FENCING DESTROYED XXXX");
        SetTimerStatus(false);
        super.onDestroy();
    }

    public static void enqueueWork(Context context, Intent intent) {
        Toast.makeText(context, "ENQUING FIRST PHASE", Toast.LENGTH_LONG).show();
        enqueueWork(context, GeofenceTransitionsJobIntentService.class, JOB_ID, intent);
    }


    @Override
    protected void onHandleWork(Intent intent) {
        new Handler(Looper.getMainLooper()).post(new Runnable() {
            @Override
            public void run() {
                try {
                    Toast.makeText(geocontext, "ENQUING FINAL PHASE", Toast.LENGTH_LONG).show();
                }catch (Exception ex){

                }
            }
        });


        GeofencingEvent geofencingEvent = GeofencingEvent.fromIntent(intent);

        if (geofencingEvent.hasError()) {
            Log.e(IDENTIFIER, "" + getErrorString(geofencingEvent.getErrorCode()));
            return;
        }

        Log.i(IDENTIFIER, geofencingEvent.toString());

        geofenceTransition = geofencingEvent.getGeofenceTransition();

        if (geofenceTransition == Geofence.GEOFENCE_TRANSITION_ENTER ||
                geofenceTransition == Geofence.GEOFENCE_TRANSITION_EXIT) {

            //logic to process geofence event
        }
    }

    private String getGeofenceTransitionInfo(List<Geofence> triggeringGeofences) {
        ArrayList<String> locationNames = new ArrayList<>();
        for (Geofence geofence : triggeringGeofences) {
            locationNames.add(getLocationName(geofence.getRequestId()));
            System.out.println("GET LOACTION NAME");
        }
        String triggeringLocationsString = TextUtils.join(", ", locationNames);

        return triggeringLocationsString;
    }

    private String getLocationName(String key) {
        String[] strs = key.split("-");

        String locationName = null;
        if (strs != null && strs.length == 2) {
            double lat = Double.parseDouble(strs[0]);
            double lng = Double.parseDouble(strs[1]);
            locationName = getLocationNameGeocoder(lat, lng);
        } else System.out.println("NULLLLLLLLLLLLLLLLL");
        if (locationName != null) {
            return locationName;
        } else {
            return key;
        }
    }

    private String getLocationNameGeocoder(double lat, double lng) {
        Geocoder geocoder = new Geocoder(this, Locale.getDefault());
        List<Address> addresses = null;

        try {
            addresses = geocoder.getFromLocation(lat, lng, 1);
        } catch (Exception ioException) {
            Log.e("", "Error in getting location name for the location");
            Toast.makeText(this, "Error in getting location name for the location", Toast.LENGTH_LONG).show();
        }

        if (addresses == null || addresses.size() == 0) {
            Log.d("", "no location name");
            Toast.makeText(this, "No Location name", Toast.LENGTH_LONG).show();

            return null;
        } else {
            Address address = addresses.get(0);
            ArrayList<String> addressInfo = new ArrayList<>();
            for (int i = 0; i <= address.getMaxAddressLineIndex(); i++) {
                addressInfo.add(address.getAddressLine(i));
            }

            return TextUtils.join(System.getProperty("line.separator"), addressInfo);
        }
    }

    private String getErrorString(int errorCode) {
        switch (errorCode) {
            case GeofenceStatusCodes.GEOFENCE_NOT_AVAILABLE:
                return "Geofence not available";
            case GeofenceStatusCodes.GEOFENCE_TOO_MANY_GEOFENCES:
                return "geofence too many_geofences";
            case GeofenceStatusCodes.GEOFENCE_TOO_MANY_PENDING_INTENTS:
                return "geofence too many pending_intents";
            default:
                return "geofence error";
        }
    }

    private String getTransitionString(int transitionType) {
        switch (transitionType) {
            case Geofence.GEOFENCE_TRANSITION_ENTER:
                return "location entered";
            case Geofence.GEOFENCE_TRANSITION_EXIT:
                return "location exited";
            case Geofence.GEOFENCE_TRANSITION_DWELL:
                return "dwell at location";
            default:
                return "location transition";
        }
    }

    private void notifyLocationAlert(String locTransitionType, String locationDetails) {

        // Create an Intent for the activity you want to start
        Intent resultIntent = new Intent(this, SettingTabMainMapActivity.class);
        // Create the TaskStackBuilder and add the intent, which inflates the back stack
        TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
        stackBuilder.addNextIntentWithParentStack(resultIntent);
        // Get the PendingIntent containing the entire back stack
        PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);

        String CHANNEL_ID = "Zoftino";
        NotificationCompat.Builder builder =
                new NotificationCompat.Builder(geocontext, CHANNEL_ID)
                        .setSmallIcon(R.drawable.mmw_red_white_60)
                        .setContentTitle(locTransitionType)
                        .setContentText(locationDetails)
                        .setContentIntent(resultPendingIntent)
                        .setPriority(NotificationManager.IMPORTANCE_HIGH);

        //Vibration
        builder.setVibrate(new long[]{1000, 1000, 1000, 1000, 1000});

        //LED
        builder.setLights(Color.RED, 10000, 10000);


        builder.setAutoCancel(true);

        NotificationManager mNotificationManager =
                (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

        mNotificationManager.notify(0, builder.build());
    }

    private void triggerDetection() {
        Log.d("sender", "Broadcasting message");
        Intent intent = new Intent("trigger-detection");
        // You can also include some extra data.
        intent.putExtra("clear", "This is my message6!");
        LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
    }

    private void triggerGeofence(double lat, double longs) {

        Patient patient = (Patient) MedWatchApp.getCurrentUser();

        if (geofenceTransition == Geofence.GEOFENCE_TRANSITION_EXIT) {

           //alert geofence exit
        }

        else if (geofenceTransition == Geofence.GEOFENCE_TRANSITION_ENTER) {

        //alert geofence entrance
    }

    static void SetTimerStatus(boolean start){
        try{
            if(!start) {
                timer.cancel();
                timer = null;
            }
            else{
                if(timer==null){
                    timer = new CountDownTimer(3600000, 5000) {
                        @Override
                        public void onTick(long l) {
                            if(GEOFENCING_CLIENT == null){
                                Log.i(TAG, "onTick: GEO CLIENT NULL");
                            }else{
                                Log.i(TAG, "onTick: OK GEO CLIENT NOT NULL");
                            }
                            if(geocontext == null){
                                Log.i(TAG, "onTick: CONTEXT NULLLL");
                            }else{
                                Log.i(TAG, "onTick: CONTEXT FINE");
                            }
                        }

                        @Override
                        public void onFinish() {

                        }
                    };
                    timer.start();
                }
            }
        }catch (Exception ex){

        }
    }

    public static void SetGeofenceClient(GeofencingClient client){
        GEOFENCING_CLIENT = client;
    }

    public static void ResetGeofenceClient(){
        GEOFENCING_CLIENT = null;
    }
    public static GeofencingClient GetGeofenceingClient(){
        return GEOFENCING_CLIENT;
//        return  null;
    }
    public static void SetGeoContext(Context context){
        geocontext = context;
    }

    private static void PrepareGeoClient(){
        if(GEOFENCING_CLIENT==null){
            mGeofenceList = new ArrayList<>();
            PrepareAllGeoCoordinate(-33.8502747,151.032907,20);
            PrepareAllGeoCoordinate(-33.8502747,151.029999,20);
            PrepareAllGeoCoordinate(-33.8492767,151.0328641,20);
            PrepareAllGeoCoordinate(-33.8499534,151.0297315,10);
            PrepareAllGeoCoordinate(-33.8500069,151.0297422,10);
            PrepareAllGeoCoordinate(-33.8500247,151.0297529,10);
            GEOFENCING_CLIENT = LocationServices.getGeofencingClient(geocontext);
            //createLocationRequest();
            RemoveGeoLocations();
        }
        AddGeoLocation();
    }

    //specifications of real location updates.
    protected static void createLocationRequest() {
        mLocationRequest = LocationRequest.create();
        mLocationRequest.setInterval(2000);
        mLocationRequest.setFastestInterval(2000);
        mLocationRequest.setSmallestDisplacement(10);
        mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
    }

    protected static void RemoveGeoLocations(){
        GEOFENCING_CLIENT.removeGeofences(getGeofencePendingIntent()).addOnCompleteListener(new OnCompleteListener<Void>() {
            @Override
            public void onComplete(@NonNull Task<Void> task) {
                if(task.isSuccessful()){
                    Toast.makeText(geocontext, "REMOVED>>>", Toast.LENGTH_LONG).show();
                }else{
                    Toast.makeText(geocontext, "FALED REMOVED>>>", Toast.LENGTH_LONG).show();
                }

            }
        });
    }

protected static void AddGeoLocation(){
    if (ActivityCompat.checkSelfPermission(geocontext, 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;
    }
    GEOFENCING_CLIENT.addGeofences(getGeofencingRequest(), getGeofencePendingIntent())
            .addOnCompleteListener(new OnCompleteListener<Void>() {
                @Override
                public void onComplete(@NonNull Task<Void> task) {
                    if (task.isSuccessful()) {
                        Toast.makeText(geocontext,
                                "Location alter has been added",
                                Toast.LENGTH_SHORT).show();
                    } else {
                        Toast.makeText(geocontext,
                                "Geofence could not be added",
                                Toast.LENGTH_SHORT).show();
                    }
                }
            });
}
//geofence triggering alert process
private static PendingIntent getGeofencePendingIntent() {
    // Reuse the PendingIntent if we already have it.
    if (mGeofencePendingIntent != null) {
        return mGeofencePendingIntent;
    }
    Intent intent = new Intent(geocontext, GeofenceBroadcastReceiver.class);
    mGeofencePendingIntent = PendingIntent.getBroadcast(geocontext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
    return mGeofencePendingIntent;
}
//geofence triggering alert process
private static GeofencingRequest getGeofencingRequest(Geofence geofence) {
    // The INITIAL_TRIGGER_ENTER flag indicates that geofencing service should trigger a
    // GEOFENCE_TRANSITION_ENTER notification when the geofence is added and if the device
    // is already inside that geofence.
    GeofencingRequest.Builder builder = new GeofencingRequest.Builder();
    // builder.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER);
    builder.addGeofence(geofence);
//        builder.setInitialTrigger(4);



    builder.addGeofences(mGeofenceList);
    return builder.build();
}

//geofence triggering alert process
private static GeofencingRequest getGeofencingRequest() {
        GeofencingRequest.Builder builder = new GeofencingRequest.Builder();
        // The INITIAL_TRIGGER_ENTER flag indicates that geofencing service should trigger a
        // GEOFENCE_TRANSITION_ENTER notification when the geofence is added and if the device
        // is already inside that geofence.
//        builder.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER |GeofencingRequest.INITIAL_TRIGGER_DWELL);
        builder.addGeofences(mGeofenceList);
        return builder.build();
    }
public static void SetGeoParams(double lat, double lng, float rad){
        latitude = lat;
        longitude = lng;
        radius = rad;
    }

private static void PrepareAllGeoCoordinate(double lat, double lng, int rad){
    //Create dummy data for testing
            mGeofenceList.add(new Geofence.Builder()
                    .setRequestId(String.format("%f-%f",lat,lng))
                    .setCircularRegion(
                            lat,
                            lng,
                            rad
                    )
                    .setLoiteringDelay(60000)
                    .setExpirationDuration(Geofence.NEVER_EXPIRE)
                    .setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER |
                            Geofence.GEOFENCE_TRANSITION_EXIT | Geofence.GEOFENCE_TRANSITION_DWELL)

                    // Create the geofence.
                    .build());
            //
        }
    }


    I set the context from MainActivity calling following method in onCreate method:
    void PrepareGeoFence(){
    //        -33.8502747,151.032907
            GeofenceTransitionsJobIntentService.SetGeoContext(this);
            GeofenceTransitionsJobIntentService.SetGeoParams(-33.8502747,
    //                151.029999
                    151.032907,
                    10f);
    this.startService(new Intent(this, GeofenceTransitionsJobIntentService.class));
        }

1 个答案:

答案 0 :(得分:1)

  1. 是的-即使您的应用程序进程被杀死,“广播”接收器句柄也会使它保持活动状态,然后您就可以开始处理事件了。
  2. 由哪个Android组件创建地理围栏都没关系