/******************************************************************************* * Created by Orlando Aliaga * Copyright 2015 Prey Inc. All rights reserved. * License: GPLv3 * Full license at "/LICENSE" ******************************************************************************/ package com.prey.actions.geofences; import android.Manifest; import android.app.PendingIntent; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.os.Build; import android.os.Bundle; import android.support.v4.app.ActivityCompat; import com.google.android.gms.common.ConnectionResult; import com.google.android.gms.common.api.GoogleApiClient; import com.google.android.gms.common.api.PendingResult; 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.LocationServices; import com.prey.FileConfigReader; import com.prey.PreyConfig; import com.prey.PreyLogger; import com.prey.json.UtilJson; import com.prey.net.PreyWebServices; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; public class GeofenceController { private static GeofenceController INSTANCE; private GoogleApiClient mGoogleApiClient = null; private List<GeofenceDto> listBD = null; private List<GeofenceDto> listWeb = null; private Map<String, GeofenceDto> mapBD = null; private Map<String, GeofenceDto> mapWeb = null; private GeofenceDataSource dataSource = null; public static GeofenceController getInstance() { if (INSTANCE == null) { INSTANCE = new GeofenceController(); } return INSTANCE; } public void run(final Context ctx) { try { mGoogleApiClient = connectGoogleApiClient(ctx); dataSource = new GeofenceDataSource(ctx); listBD = dataSource.getAllGeofences(); mapBD = convertMap(listBD); listWeb = GeofecenceParse.getJSONFromUrl(ctx); mapWeb = convertMap(listWeb); deleteZones(ctx); addZones(ctx); } catch (Exception e) { } } private Map<String, GeofenceDto> convertMap(List<GeofenceDto> list) { Map<String, GeofenceDto> map = new HashMap<String, GeofenceDto>(); for (int i = 0; list != null && i < list.size(); i++) { GeofenceDto geo = list.get(i); map.put(geo.getId(), geo); } return map; } private void deleteZones(final Context ctx) { List<String> removeList = new ArrayList<String>(); for (int i = 0; listBD != null && i < listBD.size(); i++) { GeofenceDto geo = listBD.get(i); if (!mapWeb.containsKey(geo.getId())) { PreyLogger.d("remove id:" + geo.getId()); dataSource.deleteGeofence(geo.getId()); String lastEvent=PreyConfig.getPreyConfig(ctx).getLastEvent(); if(lastEvent!=null&&lastEvent.indexOf( geo.getId())>=0) { PreyConfig.getPreyConfig(ctx).setLastEventGeo(""); } removeList.add(geo.getId()); } } if (removeList != null && removeList.size() > 0) { LocationServices.GeofencingApi.removeGeofences(mGoogleApiClient, removeList); String infoDelete = "["; for (int i = 0; removeList != null && i < removeList.size(); i++) { infoDelete += removeList.get(i); if (i + 1 < removeList.size()) { infoDelete += ","; } } infoDelete += "]"; PreyLogger.d("infoDelete:" + infoDelete); sendNotify(ctx, UtilJson.makeMapParam("start", "geofencing", "stopped", infoDelete)); } } public void deleteAllZones(Context ctx) { List<String> removeList = new ArrayList<String>(); for (int i = 0; listBD != null && i < listBD.size(); i++) { GeofenceDto geo = listBD.get(i); dataSource.deleteGeofence(geo.getId()); String lastEvent=PreyConfig.getPreyConfig(ctx).getLastEvent(); if(lastEvent!=null&&lastEvent.indexOf( geo.getId())>=0) { PreyConfig.getPreyConfig(ctx).setLastEventGeo(""); } removeList.add(geo.getId()); } if (removeList != null && removeList.size() > 0) { LocationServices.GeofencingApi.removeGeofences(mGoogleApiClient, removeList); } } public void sendNotify(final Context ctx, final Map<String, String> params) { new Thread() { public void run() { PreyWebServices.getInstance().sendNotifyActionResultPreyHttp(ctx, params); } }.start(); } private void addZones(final Context ctx) { List<com.google.android.gms.location.Geofence> mGeofenceList = new ArrayList<Geofence>(); final List<GeofenceDto> listToBdAdd = new ArrayList<GeofenceDto>(); String infoAdd = "["; for (int i = 0; listWeb != null && i < listWeb.size(); i++) { GeofenceDto geo = listWeb.get(i); if (!mapBD.containsKey(geo.getId())) { listToBdAdd.add(geo); PreyLogger.d("__[START]___________id:" + geo.name + " lat:" + geo.latitude + " long:" + geo.longitude + " ra:" + geo.radius + " expires:" + geo.expires); int transitionTypes = com.google.android.gms.location.Geofence.GEOFENCE_TRANSITION_ENTER | com.google.android.gms.location.Geofence.GEOFENCE_TRANSITION_DWELL | com.google.android.gms.location.Geofence.GEOFENCE_TRANSITION_EXIT; mGeofenceList.add(new com.google.android.gms.location.Geofence.Builder() .setRequestId(geo.id) .setCircularRegion(geo.latitude, geo.longitude, geo.radius) .setExpirationDuration(Geofence.NEVER_EXPIRE) .setTransitionTypes(transitionTypes) .setLoiteringDelay(FileConfigReader.getInstance(ctx).getGeofenceLoiteringDelay()) .build()); infoAdd += geo.id; if (i + 1 < listWeb.size()) { infoAdd += ","; } } } infoAdd += "]"; final String infoExtra = infoAdd; PreyLogger.d("infoAdd:" + infoExtra); GeofencingRequest.Builder builder = new GeofencingRequest.Builder(); builder.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER); builder.addGeofences(mGeofenceList); GeofencingRequest geofencingRequest = builder.build(); if (mGoogleApiClient.isConnected()) { PreyLogger.d("---->isConnected"); try { Intent intent = new Intent(ctx, GeofenceIntentService.class); PendingIntent pendingIntent = PendingIntent.getService(ctx, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.M ||ActivityCompat.checkSelfPermission(ctx, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) { PendingResult<Status> result = LocationServices.GeofencingApi.addGeofences( mGoogleApiClient, geofencingRequest, pendingIntent ); result.setResultCallback(new ResultCallback<Status>() { @Override public void onResult(Status status) { PreyLogger.d("*********************connectionAddListener status"); if (status.isSuccess()) { PreyLogger.d("********saveGeofence"); sendNotify(ctx, UtilJson.makeMapParam("start", "geofencing", "started", infoExtra)); GeofenceDataSource dataSource = new GeofenceDataSource(ctx); for (int i = 0; listToBdAdd != null && i < listToBdAdd.size(); i++) { dataSource.createGeofence(listToBdAdd.get(i)); } } else { PreyLogger.d("*********************Registering geofence failed: " + status.getStatusMessage() + " : " + status.getStatusCode()); sendNotify(ctx, UtilJson.makeMapParam("start", "geofencing", "failed", "status:" + status.isSuccess())); } } }); } } catch (Exception e) { PreyLogger.e("error ---->isConnected:" + e.getMessage(), e); sendNotify(ctx, UtilJson.makeMapParam("start", "geofencing", "failed", "error:" + e.getMessage())); } } else { PreyLogger.d("not connect mGoogleApiClient 3"); sendNotify(ctx, UtilJson.makeMapParam("start", "geofencing", "failed", "not connect mGoogleApiClient")); } } public void init(final Context ctx) { PreyLogger.d("_GeofenceController__init"); GoogleApiClient mGoogleApiClient = null; try { mGoogleApiClient = connectGoogleApiClient(ctx); GeofenceDataSource dataSource = new GeofenceDataSource(ctx); List<GeofenceDto> listBD = dataSource.getAllGeofences(); List<com.google.android.gms.location.Geofence> mGeofenceList = new ArrayList<Geofence>(); final List<GeofenceDto> listToBdAdd = new ArrayList<GeofenceDto>(); String info = "["; for (int i = 0; listBD != null && i < listBD.size(); i++) { GeofenceDto geo = listBD.get(i); listToBdAdd.add(geo); PreyLogger.d("__[START]___________id:" + geo.name + " lat:" + geo.latitude + " long:" + geo.longitude + " ra:" + geo.radius + " expires:" + geo.expires); int transitionTypes = com.google.android.gms.location.Geofence.GEOFENCE_TRANSITION_ENTER | com.google.android.gms.location.Geofence.GEOFENCE_TRANSITION_DWELL | com.google.android.gms.location.Geofence.GEOFENCE_TRANSITION_EXIT; mGeofenceList.add(new com.google.android.gms.location.Geofence.Builder() .setRequestId(geo.id) .setCircularRegion(geo.latitude, geo.longitude, geo.radius) .setExpirationDuration(Geofence.NEVER_EXPIRE) .setTransitionTypes(transitionTypes) .setLoiteringDelay(FileConfigReader.getInstance(ctx).getGeofenceLoiteringDelay()) .build()); info += geo.id; if (i + 1 < listBD.size()) { info += ","; } } info += "]"; final String extraInfo = info; PreyLogger.d("info:" + extraInfo); GeofencingRequest.Builder builder = new GeofencingRequest.Builder(); builder.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER); builder.addGeofences(mGeofenceList); GeofencingRequest geofencingRequest = builder.build(); if (mGoogleApiClient.isConnected()) { PreyLogger.d("---->isConnected"); try { if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.M ||ActivityCompat.checkSelfPermission(ctx, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) { Intent intent = new Intent(ctx, GeofenceIntentService.class); PendingIntent pendingIntent = PendingIntent.getService(ctx, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); PendingResult<Status> result = LocationServices.GeofencingApi.addGeofences( mGoogleApiClient, geofencingRequest, pendingIntent ); result.setResultCallback(new ResultCallback<Status>() { @Override public void onResult(Status status) { PreyLogger.d("*********************connectionAddListener status :" + status); if (status.isSuccess()) { PreyLogger.d("********saveGeofence"); } else { PreyLogger.d("*********************Registering geofence failed: " + status.getStatusMessage() + " : " + status.getStatusCode()); sendNotify(ctx, UtilJson.makeMapParam("start", "geofencing", "failed", "status:" + status.isSuccess())); } } }); } } catch (Exception e) { PreyLogger.e("error ---->isConnected:" + e.getMessage(), e); sendNotify(ctx, UtilJson.makeMapParam("start", "geofencing", "failed", "error:" + e.getMessage())); } } else { PreyLogger.d("not connect mGoogleApiClient 3"); sendNotify(ctx, UtilJson.makeMapParam("start", "geofencing", "failed", "not connect mGoogleApiClient")); } } catch (Exception e) { } } private GoogleApiClient connectGoogleApiClient(Context ctx) { GoogleApiClient mGoogleApiClient = null; try { mGoogleApiClient = buildGoogleApiClient(ctx); int i = 0; while (i < 50 && !mGoogleApiClient.isConnected()) { mGoogleApiClient.connect(); i++; Thread.sleep(1000); if (i % 10 == 0) { buildGoogleApiClient(ctx); } PreyLogger.d("___[" + i + "] sleep"); } } catch (Exception e) { PreyLogger.e("error:" + e.getMessage(), e); } return mGoogleApiClient; } private void disconnectGoogleApiClient(GoogleApiClient mGoogleApiClient) { try { if (mGoogleApiClient != null) { mGoogleApiClient.disconnect(); } } catch (Exception e) { PreyLogger.e("error:" + e.getMessage(), e); } } private synchronized GoogleApiClient buildGoogleApiClient(Context ctx) { GoogleApiClient mGoogleApiClient = new GoogleApiClient.Builder(ctx) .addConnectionCallbacks(new GoogleApiClient.ConnectionCallbacks() { @Override public void onConnected(Bundle bundle) { PreyLogger.d("________________Connected to GoogleApiClient"); } @Override public void onConnectionSuspended(int i) { PreyLogger.d("________________Connection suspended"); } }) .addOnConnectionFailedListener(new GoogleApiClient.OnConnectionFailedListener() { @Override public void onConnectionFailed(ConnectionResult connectionResult) { PreyLogger.d("________________Connection failed: ConnectionResult.getErrorCode() = " + connectionResult.getErrorCode()); } }) .addApi(LocationServices.API) .build(); return mGoogleApiClient; } }