Android Geo-fence无法正常工作

时间:2016-11-23 05:18:17

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

我正在使用geofence api进行接近但它无法正常工作。有时它会在同一位置给出范围和范围。

我也在使用GPS库来提高地理范围内的范围 - 但是它仍然无法正常工作。我正在使用以下代码进行地理围栏:

我使用半径300米考虑inrange-outrange(进入 - 退出)

的AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.geofencedemo">

<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

<application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:supportsRtl="true"
    android:theme="@style/AppTheme">
    <activity android:name=".MainActivity">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
    <activity
        android:name=".CheckPermission"
        android:screenOrientation="portrait"
        android:theme="@style/DialogActivity" />

    <receiver
        android:name="services.GeofenceTransitionsReceiver"
        android:enabled="true"
        android:exported="false">
        <intent-filter>
            <action android:name="com.geofencedemo.ACTION_RECEIVE_GEOFENCE" />
            <category android:name="com.geofencedemo" />
        </intent-filter>
    </receiver>
    <service
        android:name="services.GeofenceTransitionsIntentService"
        android:exported="false" />
</application>

MainActivity.java(用于注册地理围栏)

public class MainActivity extends Activity implements com.google.android.gms.location.LocationListener {

private LocationManager locationManager;
private LocationRequest mLocationRequest;
private GoogleApiClient mGoogleApiClient;
private final float GEOFENCE_RADIUS_IN_METERS = 300;//Meter(s)
private final long GEOFENCE_EXPIRATION_IN_MILLISECONDS =    Geofence.NEVER_EXPIRE;
private int GEOFENCE_TRANSITION_ENTER = 1;
private int GEOFENCE_TRANSITION_EXIT = 2;
private List<Geofence> mGeofenceList;
private String geofenceID = "testGeofence";
private SharedPreferences preferences;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    preferences = getSharedPreferences("ISSKEYGEOFENCE-prefs", MODE_PRIVATE);
    locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);

    Button btnSetLocation = (Button) findViewById(R.id.btn_setlocation);
    btnSetLocation.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            boolean isGPSEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
            if (!isGPSEnabled) {
                Toast.makeText(getApplicationContext(), "Please enable Location service to allow set location", Toast.LENGTH_LONG).show();
                return;
            }
            if(Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP_MR1){
                Log.d("myTag", "check marshmallow permission...");
                Intent permissionIntent = new Intent(MainActivity.this, CheckPermission.class);
                startActivityForResult(permissionIntent, 1111);
            } else {
                intGoogleAPI();
            }
        }
    });
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    switch (requestCode) {
        case 1111:
            if (resultCode == RESULT_OK) {
                intGoogleAPI();
            }
            break;
    }
}

private void intGoogleAPI() {
    mLocationRequest = LocationRequest.create();
    mLocationRequest.setInterval(3000);
    mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
    mLocationRequest.setFastestInterval(1000);
    mGeofenceList = new ArrayList<Geofence>(1);
    mGoogleApiClient = new GoogleApiClient.Builder(MainActivity.this).addApi(LocationServices.API).addConnectionCallbacks(new GoogleApiClient.ConnectionCallbacks() {
        @Override
        public void onConnected(final Bundle bundle) {
            if (isServiceConnected()) {
                Log.d("myTag", "request for update current location");
                LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, MainActivity.this);
            }
        }

        @Override
        public void onConnectionSuspended(final int cause) {}
    }).addOnConnectionFailedListener(new GoogleApiClient.OnConnectionFailedListener() {
        @Override
        public void onConnectionFailed(final ConnectionResult connectionResult) {}
    }).build();
    mGoogleApiClient.connect();
}

private boolean isServiceConnected() {
    int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(MainActivity.this);
    return ConnectionResult.SUCCESS == resultCode;
}

@Override
public void onLocationChanged(Location mLastLocation) {
    if (isServiceConnected()) {
        Log.d("myTag", "request removed location update");
        LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);
    }
    try {
        addLocation(mLastLocation.getLatitude(), mLastLocation.getLongitude());
    } catch (Exception e) {}
}

public void addLocation(final double latitude, final double longitude) {
    Log.v("myTag", "set lcation lat: " + latitude);
    Log.v("myTag", "set lcation lag: " + longitude);
    mGeofenceList.add(new Geofence.Builder().setRequestId(geofenceID).setTransitionTypes(GEOFENCE_TRANSITION_ENTER | GEOFENCE_TRANSITION_EXIT).setCircularRegion(latitude, longitude, GEOFENCE_RADIUS_IN_METERS).setExpirationDuration(GEOFENCE_EXPIRATION_IN_MILLISECONDS).build());
    final List<String> GEO_FENCE_ID_LIST = new ArrayList<String>();
    GEO_FENCE_ID_LIST.add(geofenceID);
    if (mGoogleApiClient != null) {
        LocationServices.GeofencingApi.removeGeofences(mGoogleApiClient, GEO_FENCE_ID_LIST).setResultCallback(new ResultCallback<Status>() {
            @Override
            public void onResult(final Status status) {
                if (status.isSuccess()) {
                    // successfully removed geofence...
                    Log.d("myTag", "removed old geofence successfully ");
                } else {
                    Log.d("myTag", "Not removed old geofence");
                }
            }
        });
    }

    if (mGoogleApiClient != null) {
        LocationServices.GeofencingApi.addGeofences(mGoogleApiClient, getGeofencingRequest(), getGeofencePendingIntent()).setResultCallback(new ResultCallback<Status>() {
            @Override
            public void onResult(final Status status) {
                if (status.isSuccess()) {
                    // successfully Added geofence...
                    Log.d("myTag", "New geofence successfully added");
                    Toast.makeText(getApplicationContext(), "Successfully added geofence", Toast.LENGTH_LONG).show();
                    SharedPreferences.Editor editor = preferences.edit();
                    editor.putBoolean("isinrange", false);
                    editor.putString("lat", String.valueOf(latitude));
                    editor.putString("log", String.valueOf(longitude));
                    editor.apply();
                }
                try {
                    if (isServiceConnected()) {
                        LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, MainActivity.this);
                    }
                    mGoogleApiClient.disconnect();
                } catch (Exception e) {}
            }
        });
    }
}

private GeofencingRequest getGeofencingRequest() {
    GeofencingRequest.Builder builder = new GeofencingRequest.Builder();
    builder.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_EXIT);
    builder.addGeofences(mGeofenceList);
    return builder.build();
}

private PendingIntent getGeofencePendingIntent() {
    Intent intent = new Intent("com.geofencedemo.ACTION_RECEIVE_GEOFENCE");
    return PendingIntent.getBroadcast(MainActivity.this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
}
}

GeofenceTransitionsIntentService(触发范围内,地理围栏超出范围)

public class GeofenceTransitionsIntentService extends IntentService implements com.google.android.gms.location.LocationListener {

public GeofenceTransitionsIntentService() {
    super("GeofenceTransitionsIntentService");
}

@Override
public void onCreate() {
    super.onCreate();
    preferences = getSharedPreferences("ISSKEYGEOFENCE-prefs", MODE_PRIVATE);
}

private LocationRequest mLocationRequest;
private GoogleApiClient mGoogleApiClient;
private boolean isLocationFetched = false;
private String geofenceTransitionIds;
private boolean isInRange = false;
private SharedPreferences preferences;

@Override
protected void onHandleIntent(final Intent intent) {
    if (intent.getExtras() != null) {
        int geofenceTransitionType = intent.getIntExtra("TransitionType", 4);
        geofenceTransitionIds = intent.getStringExtra("TransitionId");

        /*final String lat = intent.getStringExtra("TransitionId_lat");
        final String log = intent.getStringExtra("TransitionId_log");*/

        if (geofenceTransitionIds != null && geofenceTransitionIds.length() > 0) {
            switch (geofenceTransitionType) {
                case Geofence.GEOFENCE_TRANSITION_ENTER:
                    geofenceTransitionIds(geofenceTransitionIds, true);
                    //new IntGoogleApiClient(appStorage, null, true).Intialize();
                    //processIn(geofenceTransitionIds, lat, log);
                    break;
                case Geofence.GEOFENCE_TRANSITION_EXIT:
                    geofenceTransitionIds(geofenceTransitionIds, false);
                    //new IntGoogleApiClient(appStorage, null, true).Intialize();
                    //processOut(geofenceTransitionIds, lat, log);
                    break;
            }
        }
    }
}

private void geofenceTransitionIds (String geofenceTransitionIds, boolean isEnteCall) {
    if (geofenceTransitionIds != null && geofenceTransitionIds.length() > 0) {
        isInRange = isEnteCall;
        intGoogleAPI();
    }
}

private void intGoogleAPI() {
    mLocationRequest = LocationRequest.create();
    mLocationRequest.setInterval(3000);
    mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
    mLocationRequest.setFastestInterval(1000);
    mGoogleApiClient = new GoogleApiClient.Builder(GeofenceTransitionsIntentService.this).addApi(LocationServices.API).addConnectionCallbacks(new GoogleApiClient.ConnectionCallbacks() {
        @Override
        public void onConnected(final Bundle bundle) {
            if (isServiceConnected()) {
                // please consider here location permission is already allowed...
                LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, GeofenceTransitionsIntentService.this);
            }
        }

        @Override
        public void onConnectionSuspended(final int cause) {}
    }).addOnConnectionFailedListener(new GoogleApiClient.OnConnectionFailedListener() {
        @Override
        public void onConnectionFailed(final ConnectionResult connectionResult) {}
    }).build();
    mGoogleApiClient.connect();
}

private boolean isServiceConnected() {
    int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(GeofenceTransitionsIntentService.this);
    return ConnectionResult.SUCCESS == resultCode;
}

@Override
public void onLocationChanged(Location passedLocation) {
    if (passedLocation != null && !isLocationFetched) {
        if (isServiceConnected()) {
            LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, GeofenceTransitionsIntentService.this);
        }
        isLocationFetched = true;
        try {
            if (geofenceTransitionIds != null && geofenceTransitionIds.length() > 0) {
                if (isInRange) {
                    processIn(geofenceTransitionIds, String.valueOf(passedLocation.getLatitude()), String.valueOf(passedLocation.getLongitude()));
                } else {
                    processOut(geofenceTransitionIds, String.valueOf(passedLocation.getLatitude()), String.valueOf(passedLocation.getLongitude()));
                }
            }
        } catch (Exception e) {}
        disconnectGoogleClient();
    }
}

private void disconnectGoogleClient() {
    try {
        if (mGoogleApiClient != null) {
            if (isServiceConnected()) {
                LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, GeofenceTransitionsIntentService.this);
            }
            mGoogleApiClient.disconnect();
        }
    } catch (Exception e) {}
}

private void processIn(String passedIds, String lat, String log) {
    if (passedIds != null) {
        List<String> items = Arrays.asList(passedIds.split("\\s*,\\s*"));

        for (String deviceName : items) {
            if (deviceName != null) {
                boolean isOutRange = preferences.getBoolean("isinrange", false);
                if (mappingRadius(true, deviceName, lat, log) && isOutRange) {
                    SharedPreferences.Editor editor = preferences.edit();
                    editor.putBoolean("isinrange", false);
                    editor.apply();
                    sendNotification(GeofenceTransitionsIntentService.this, "In range come!", Color.BLACK);
                }
            }
        }
    }
}

private void processOut(String passedIds, String lat, String log) {
    if (passedIds != null) {
        List<String> items = Arrays.asList(passedIds.split("\\s*,\\s*"));
        for (String deviceName : items) {
            if (deviceName != null) {
                boolean isInRange = preferences.getBoolean("isinrange", false);
                if (mappingRadius(false, deviceName, lat, log) && !isInRange) {
                    SharedPreferences.Editor editor = preferences.edit();
                    editor.putBoolean("isinrange", true);
                    editor.apply();
                    sendNotification(GeofenceTransitionsIntentService.this, "Out range come!", Color.RED);
                }
            }
        }
    }
}

private boolean mappingRadius(boolean isInRange, String deviceName, String currentLat, String currentLog) {
    final float cLat = Float.parseFloat(currentLat);
    final float cLog = Float.parseFloat(currentLog);
    Log.d("myTag", "GeofenceTransitionsReceiver lat " + cLat);
    Log.d("myTag", "GeofenceTransitionsReceiver log " + cLog);

    float appLat;
    float appLog;
    appLat = Float.parseFloat(preferences.getString("lat", "0.0"));
    appLog = Float.parseFloat(preferences.getString("log", "0.0"));
    Log.d("myTag", "GeofenceTransitionsReceiver app lat " + appLat);
    Log.d("myTag", "GeofenceTransitionsReceiver app log " + appLog);

    Location current_latlog = new Location("crntlocation");
    current_latlog.setLatitude(appLat);
    current_latlog.setLongitude(appLog);

    Location new_latlog = new Location("newlocation");
    new_latlog.setLatitude(cLat);
    new_latlog.setLongitude(cLog);

    final double distance = current_latlog.distanceTo(new_latlog);
    Log.v("myTag", "GeofenceTransitionsReceiver calculation distance is: " + distance);
    //if (distance < 2000) {
        if (isInRange) {
            if (distance <= 300) { // with in 300 Meters consider as in range...
                return true;
            } else {
                return false;
            }
        } else {
            if (distance >= 300) { // more than 300 Meters consider as out range...
                return true;
            } else {
                return false;
            }
        }
    /*} else {
        return false;
    }*/
}

private void sendNotification(final Context context, String notificationMessage, int color) {
    TaskStackBuilder stackBuilder = TaskStackBuilder.create(context);
    stackBuilder.addNextIntent(new Intent());
    PendingIntent notificationPendingIntent = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_ONE_SHOT);
    NotificationCompat.Builder builder = new NotificationCompat.Builder(context);
    builder.setSmallIcon(R.mipmap.ic_launcher).setLargeIcon(BitmapFactory.decodeResource(context.getResources(), R.mipmap.ic_launcher)).setContentTitle(context.getResources().getString(R.string.app_name)).setTicker(notificationMessage).setContentText(notificationMessage).setContentIntent(notificationPendingIntent).setColor(color).setVibrate(new long[] { 1000, 1000, 1000, 1000 }).setAutoCancel(true);
    NotificationManager mNotificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
    mNotificationManager.notify((int) System.currentTimeMillis(), builder.build());
}
}

GeofenceTransitionsReceiver(处理/计算地理围栏触发后的距离)

public class GeofenceTransitionsReceiver extends WakefulBroadcastReceiver {
@Override
public void onReceive(final Context context, final Intent intent) {
    GeofencingEvent geofencingEvent = GeofencingEvent.fromIntent(intent);
    if (geofencingEvent.hasError()) {
        String errorMessage = getErrorString(context, geofencingEvent.getErrorCode());
        Log.d("myTag", "GeofenceTransitionsReceiver error " +errorMessage);
        // sendNotification(context, errorMessage, Color.RED);
        return;
    }
    int geofenceTransition = geofencingEvent.getGeofenceTransition();
    Log.d("myTag", "GeofenceTransitionsReceiver " + geofenceTransition);

    // for testing....
    //sendNotification(context, context.getResources().getString(R.string.geofence_transition_type, geofenceTransition), Color.RED);

    if (geofenceTransition == Geofence.GEOFENCE_TRANSITION_ENTER || geofenceTransition == Geofence.GEOFENCE_TRANSITION_EXIT) {
        List<Geofence> triggeringGeofences = geofencingEvent.getTriggeringGeofences();
        String geofenceTransitionIds = getGeofenceTransitionIds(triggeringGeofences);
        Location triggeringLocation = geofencingEvent.getTriggeringLocation();
        Intent serviceIntent = new Intent(context.getApplicationContext(), GeofenceTransitionsIntentService.class);
        serviceIntent.putExtra("TransitionType", geofenceTransition);
        serviceIntent.putExtra("TransitionId", geofenceTransitionIds);

        serviceIntent.putExtra("TransitionId_lat", String.valueOf(triggeringLocation.getLatitude()));
        serviceIntent.putExtra("TransitionId_log", String.valueOf(triggeringLocation.getLongitude()));

        context.startService(serviceIntent);
    } else {
        // sendNotification(context,
        // context.getResources().getString(R.string.geofence_transition_invalid_type,
        // geofenceTransition), Color.RED);
    }
}

private String getErrorString(final Context context, int errorCode) {
    Resources mResources = context.getResources();
    switch (errorCode) {
    case GeofenceStatusCodes.GEOFENCE_NOT_AVAILABLE:
        return "Geofence service is not available now";
    case GeofenceStatusCodes.GEOFENCE_TOO_MANY_GEOFENCES:
        return "Your app has registered too many geofences";
    case GeofenceStatusCodes.GEOFENCE_TOO_MANY_PENDING_INTENTS:
        return "You have provided too many PendingIntents to the addGeofences() call";
    default:
        return "Unknown error: the Geofence service is not available now";
    }
}

private String getGeofenceTransitionIds(List<Geofence> triggeringGeofences) {
    List<String> triggeringGeofencesIdsList = new ArrayList<String>();
    for (Geofence geofence : triggeringGeofences) {
        triggeringGeofencesIdsList.add(geofence.getRequestId());
    }
    return TextUtils.join(",", triggeringGeofencesIdsList);
}
}

我们还能做些什么来提高准确性并克服同一位置的范围外的问题吗?

0 个答案:

没有答案