Java tutorial
/* According to apache license This is fork of christocracy cordova-plugin-background-geolocation plugin https://github.com/christocracy/cordova-plugin-background-geolocation Differences to original version: 1. new methods isLocationEnabled, mMessageReciever, handleMessage */ package com.tenforwardconsulting.bgloc.cordova; import android.app.Activity; import android.app.Application; import android.content.Context; import android.content.pm.PackageManager; import android.provider.Settings.SettingNotFoundException; import com.marianhello.bgloc.BackgroundGeolocationFacade; import com.marianhello.bgloc.Config; import com.marianhello.bgloc.LocationService; import com.marianhello.bgloc.PluginDelegate; import com.marianhello.bgloc.PluginError; import com.marianhello.bgloc.cordova.ConfigMapper; import com.marianhello.bgloc.data.BackgroundActivity; import com.marianhello.bgloc.data.BackgroundLocation; import com.marianhello.logging.LogEntry; import com.marianhello.logging.LoggerManager; import org.apache.cordova.CallbackContext; import org.apache.cordova.CordovaPlugin; import org.apache.cordova.PluginResult; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import java.util.Collection; public class BackgroundGeolocationPlugin extends CordovaPlugin implements PluginDelegate { public static final String LOCATION_EVENT = "location"; public static final String STATIONARY_EVENT = "stationary"; public static final String ACTIVITY_EVENT = "activity"; public static final String FOREGROUND_EVENT = "foreground"; public static final String BACKGROUND_EVENT = "background"; public static final String AUTHORIZATION_EVENT = "authorization"; public static final String START_EVENT = "start"; public static final String STOP_EVENT = "stop"; public static final String ACTION_START = "start"; public static final String ACTION_STOP = "stop"; public static final String ACTION_CONFIGURE = "configure"; public static final String ACTION_SWITCH_MODE = "switchMode"; public static final String ACTION_LOCATION_ENABLED_CHECK = "isLocationEnabled"; public static final String ACTION_SHOW_LOCATION_SETTINGS = "showLocationSettings"; public static final String ACTION_SHOW_APP_SETTINGS = "showAppSettings"; public static final String ACTION_GET_STATIONARY = "getStationaryLocation"; public static final String ACTION_GET_ALL_LOCATIONS = "getLocations"; public static final String ACTION_GET_VALID_LOCATIONS = "getValidLocations"; public static final String ACTION_DELETE_LOCATION = "deleteLocation"; public static final String ACTION_DELETE_ALL_LOCATIONS = "deleteAllLocations"; public static final String ACTION_GET_CONFIG = "getConfig"; public static final String ACTION_GET_LOG_ENTRIES = "getLogEntries"; public static final String ACTION_CHECK_STATUS = "checkStatus"; public static final String ACTION_REGISTER_EVENT_LISTENER = "addEventListener"; public static final String ACTION_START_TASK = "startTask"; public static final String ACTION_END_TASK = "endTask"; public static final String ACTION_REGISTER_HEADLESS_TASK = "registerHeadlessTask"; private static final int PERMISSIONS_REQUEST_CODE = 1; private BackgroundGeolocationFacade facade; private CallbackContext callbackContext; private org.slf4j.Logger logger; @Override protected void pluginInitialize() { super.pluginInitialize(); facade = new BackgroundGeolocationFacade(this); facade.init(); logger = LoggerManager.getLogger(BackgroundGeolocationPlugin.class); } public boolean execute(String action, final JSONArray data, final CallbackContext callbackContext) { Context context = getContext(); if (ACTION_REGISTER_EVENT_LISTENER.equals(action)) { logger.debug("Registering event listeners"); this.callbackContext = callbackContext; return true; } else if (ACTION_START.equals(action)) { runOnWebViewThread(new Runnable() { public void run() { start(); } }); return true; } else if (ACTION_STOP.equals(action)) { runOnWebViewThread(new Runnable() { public void run() { facade.stop(); } }); return true; } else if (ACTION_SWITCH_MODE.equals(action)) { try { int mode = data.getInt(0); facade.switchMode(mode); } catch (JSONException e) { logger.error("Switch mode error: {}", e.getMessage()); sendError(new PluginError(PluginError.JSON_ERROR, e.getMessage())); } return true; } else if (ACTION_CONFIGURE.equals(action)) { runOnWebViewThread(new Runnable() { public void run() { try { Config config = ConfigMapper.fromJSONObject(data.getJSONObject(0)); facade.configure(config); callbackContext.success(); } catch (Exception e) { logger.error("Configuration error: {}", e.getMessage()); callbackContext.error("Configuration error: " + e.getMessage()); } } }); return true; } else if (ACTION_LOCATION_ENABLED_CHECK.equals(action)) { logger.debug("Location services enabled check"); try { callbackContext.success(facade.locationServicesEnabled() ? 1 : 0); } catch (SettingNotFoundException e) { logger.error("Location service checked failed: {}", e.getMessage()); callbackContext.error("Location setting error occured"); } return true; } else if (ACTION_SHOW_LOCATION_SETTINGS.equals(action)) { BackgroundGeolocationFacade.showLocationSettings(context); return true; } else if (ACTION_SHOW_APP_SETTINGS.equals(action)) { BackgroundGeolocationFacade.showAppSettings(context); return true; } else if (ACTION_GET_STATIONARY.equals(action)) { try { BackgroundLocation stationaryLocation = facade.getStationaryLocation(); if (stationaryLocation != null) { callbackContext.success(stationaryLocation.toJSONObject()); } else { callbackContext.success(); } } catch (JSONException e) { logger.error("Getting stationary location failed: {}", e.getMessage()); callbackContext.error("Getting stationary location failed"); } return true; } else if (ACTION_GET_ALL_LOCATIONS.equals(action)) { runOnWebViewThread(new Runnable() { public void run() { try { callbackContext.success(getAllLocations()); } catch (JSONException e) { logger.error("Getting all locations failed: {}", e.getMessage()); callbackContext.error("Converting locations to JSON failed."); } } }); return true; } else if (ACTION_GET_VALID_LOCATIONS.equals(action)) { runOnWebViewThread(new Runnable() { public void run() { try { callbackContext.success(getValidLocations()); } catch (JSONException e) { logger.error("Getting valid locations failed: {}", e.getMessage()); callbackContext.error("Converting locations to JSON failed."); } } }); return true; } else if (ACTION_DELETE_LOCATION.equals(action)) { runOnWebViewThread(new Runnable() { public void run() { try { Long locationId = data.getLong(0); facade.deleteLocation(locationId); callbackContext.success(); } catch (JSONException e) { logger.error("Delete location failed: {}", e.getMessage()); callbackContext.error("Deleting location failed: " + e.getMessage()); } } }); return true; } else if (ACTION_DELETE_ALL_LOCATIONS.equals(action)) { runOnWebViewThread(new Runnable() { public void run() { facade.deleteAllLocations(); callbackContext.success(); } }); return true; } else if (ACTION_GET_CONFIG.equals(action)) { runOnWebViewThread(new Runnable() { public void run() { try { Config config = facade.getConfig(); callbackContext.success(ConfigMapper.toJSONObject(config)); } catch (JSONException e) { logger.error("Error getting mConfig: {}", e.getMessage()); callbackContext.error("Error getting mConfig: " + e.getMessage()); } } }); return true; } else if (ACTION_GET_LOG_ENTRIES.equals(action)) { runOnWebViewThread(new Runnable() { public void run() { try { callbackContext.success(getLogs(data.getInt(0))); } catch (Exception e) { callbackContext.error("Getting logs failed: " + e.getMessage()); } } }); return true; } else if (ACTION_CHECK_STATUS.equals(action)) { runOnWebViewThread(new Runnable() { public void run() { try { callbackContext.success(checkStatus()); } catch (Exception e) { callbackContext.error("Getting logs failed: " + e.getMessage()); } } }); return true; } else if (ACTION_START_TASK.equals(action)) { callbackContext.success(1); return true; } else if (ACTION_END_TASK.equals(action)) { callbackContext.success(); return true; } else if (ACTION_REGISTER_HEADLESS_TASK.equals(action)) { logger.debug("Registering headless task"); try { facade.registerHeadlessTask(data.getString(0)); } catch (JSONException e) { callbackContext.error("Registering headless task failed: " + e.getMessage()); } return true; } return false; } private void start() { if (facade.hasPermissions()) { try { facade.start(); } catch (JSONException e) { logger.error("Configuration error: {}", e.getMessage()); sendError(new PluginError(PluginError.JSON_ERROR, e.getMessage())); } } else { logger.debug("Permissions not granted"); cordova.requestPermissions(this, PERMISSIONS_REQUEST_CODE, BackgroundGeolocationFacade.PERMISSIONS); } } /** * Called when the system is about to start resuming a previous activity. * * @param multitasking Flag indicating if multitasking is turned on for app */ public void onPause(boolean multitasking) { logger.info("App will be paused multitasking={}", multitasking); facade.switchMode(BackgroundGeolocationFacade.BACKGROUND_MODE); sendEvent(BACKGROUND_EVENT); } /** * Called when the activity will start interacting with the user. * * @param multitasking Flag indicating if multitasking is turned on for app */ public void onResume(boolean multitasking) { logger.info("App will be resumed multitasking={}", multitasking); facade.switchMode(BackgroundGeolocationFacade.FOREGROUND_MODE); sendEvent(FOREGROUND_EVENT); } /** * Called when the activity is becoming visible to the user. */ public void onStart() { logger.info("App is visible"); } /** * Called when the activity is no longer visible to the user. */ public void onStop() { logger.info("App is no longer visible"); } /** * The final call you receive before your activity is destroyed. * Checks to see if it should turn off */ @Override public void onDestroy() { logger.info("Destroying plugin"); facade.onAppDestroy(); super.onDestroy(); } @Override public Activity getActivity() { return cordova.getActivity(); } public Context getContext() { return getActivity().getApplicationContext(); } protected Application getApplication() { return getActivity().getApplication(); } private void sendEvent(String name) { if (callbackContext == null) { return; } JSONObject event = new JSONObject(); try { event.put("name", name); PluginResult result = new PluginResult(PluginResult.Status.OK, event); result.setKeepCallback(true); callbackContext.sendPluginResult(result); } catch (JSONException e) { logger.error("Error sending event {}: {}", name, e.getMessage()); } } private void sendEvent(String name, JSONObject payload) { if (callbackContext == null) { return; } JSONObject event = new JSONObject(); try { event.put("name", name); event.put("payload", payload); PluginResult result = new PluginResult(PluginResult.Status.OK, event); result.setKeepCallback(true); callbackContext.sendPluginResult(result); } catch (JSONException e) { logger.error("Error sending event {}: {}", name, e.getMessage()); } } private void sendEvent(String name, Integer payload) { if (callbackContext == null) { return; } JSONObject event = new JSONObject(); try { event.put("name", name); event.put("payload", payload); PluginResult result = new PluginResult(PluginResult.Status.OK, event); result.setKeepCallback(true); callbackContext.sendPluginResult(result); } catch (JSONException e) { logger.error("Error sending event {}: {}", name, e.getMessage()); } } private void sendError(PluginError error) { if (callbackContext == null) { return; } try { PluginResult result = new PluginResult(PluginResult.Status.ERROR, error.toJSONObject()); result.setKeepCallback(true); callbackContext.sendPluginResult(result); } catch (JSONException je) { logger.error("Error sending error {}: {}", je.getMessage()); } } private void runOnUiThread(Runnable runnable) { getActivity().runOnUiThread(runnable); } private void runOnWebViewThread(Runnable runnable) { cordova.getThreadPool().execute(runnable); } private JSONArray getAllLocations() throws JSONException { JSONArray jsonLocationsArray = new JSONArray(); Collection<BackgroundLocation> locations = facade.getLocations(); for (BackgroundLocation location : locations) { jsonLocationsArray.put(location.toJSONObjectWithId()); } return jsonLocationsArray; } private JSONArray getValidLocations() throws JSONException { JSONArray jsonLocationsArray = new JSONArray(); Collection<BackgroundLocation> locations = facade.getValidLocations(); for (BackgroundLocation location : locations) { jsonLocationsArray.put(location.toJSONObjectWithId()); } return jsonLocationsArray; } private JSONArray getLogs(Integer limit) throws Exception { JSONArray jsonLogsArray = new JSONArray(); Collection<LogEntry> logEntries = facade.getLogEntries(limit); for (LogEntry logEntry : logEntries) { jsonLogsArray.put(logEntry.toJSONObject()); } return jsonLogsArray; } private JSONObject checkStatus() throws Exception { JSONObject json = new JSONObject(); json.put("isRunning", LocationService.isRunning()); json.put("hasPermissions", facade.hasPermissions()); //@Deprecated json.put("locationServicesEnabled", facade.locationServicesEnabled()); json.put("authorization", facade.getAuthorizationStatus()); return json; } @Override public void onAuthorizationChanged(int authStatus) { sendEvent(AUTHORIZATION_EVENT, authStatus); } @Override public void onLocationChanged(BackgroundLocation location) { try { sendEvent(LOCATION_EVENT, location.toJSONObjectWithId()); } catch (JSONException e) { logger.error("Error converting location to json: {}", e.getMessage()); sendError(new PluginError(PluginError.JSON_ERROR, e.getMessage())); } } @Override public void onStationaryChanged(BackgroundLocation location) { try { sendEvent(STATIONARY_EVENT, location.toJSONObjectWithId()); } catch (JSONException e) { logger.error("Error converting location to json: {}", e.getMessage()); sendError(new PluginError(PluginError.JSON_ERROR, e.getMessage())); } } @Override public void onActitivyChanged(BackgroundActivity activity) { try { sendEvent(ACTIVITY_EVENT, activity.toJSONObject()); } catch (JSONException e) { logger.error("Error converting activity to json: {}", e.getMessage()); sendError(new PluginError(PluginError.JSON_ERROR, e.getMessage())); } } @Override public void onLocationPause() { sendEvent(STOP_EVENT); } @Override public void onLocationResume() { sendEvent(START_EVENT); } @Override public void onError(PluginError error) { sendError(error); } @Override public void onRequestPermissionResult(int requestCode, String[] permissions, int[] grantResults) throws JSONException { switch (requestCode) { case PERMISSIONS_REQUEST_CODE: { // If request is cancelled, the result arrays are empty. if (grantResults.length == 0) { // permission denied logger.info("User denied requested permissions"); onAuthorizationChanged(BackgroundGeolocationFacade.AUTHORIZATION_DENIED); return; } for (int grant : grantResults) { if (grant != PackageManager.PERMISSION_GRANTED) { // permission denied logger.info("User denied requested permissions"); onAuthorizationChanged(BackgroundGeolocationFacade.AUTHORIZATION_DENIED); return; } } // permission was granted // start service logger.info("User granted requested permissions"); facade.start(); return; } } } }