Full Code of Red-Folder/bgs-core for AI

master 00aeedab7c10 cached
13 files
67.1 KB
15.2k tokens
109 symbols
1 requests
Download .txt
Repository: Red-Folder/bgs-core
Branch: master
Commit: 00aeedab7c10
Files: 13
Total size: 67.1 KB

Directory structure:
gitextract_sh7pmjsj/

├── LICENSE
├── README.md
├── aidl/
│   └── android/
│       ├── BackgroundServiceApi.aidl
│       └── BackgroundServiceListener.aidl
├── package.json
├── plugin.xml
├── src/
│   └── android/
│       ├── BackgroundService.java
│       ├── BackgroundServicePlugin.java
│       ├── BackgroundServicePluginLogic.java
│       ├── BootReceiver.java
│       ├── PropertyHelper.java
│       └── ReflectionHelper.java
└── www/
    └── backgroundService.js

================================================
FILE CONTENTS
================================================

================================================
FILE: LICENSE
================================================
 Copyright 2013 Red Folder Consultancy Ltd
    
 Licensed under the Apache License, Version 2.0 (the "License");   
 you may not use this file except in compliance with the License.   
 You may obtain a copy of the License at       
  
 http://www.apache.org/licenses/LICENSE-2.0   
 
 Unless required by applicable law or agreed to in writing, software   
 distributed under the License is distributed on an "AS IS" BASIS,   
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   
 See the License for the specific language governing permissions and   
 limitations under the License.

================================================
FILE: README.md
================================================
# Important Notice
Please be aware that I'm no longer actively maintaining this plugin.

I believe the problem it solved is now better handled with PWA technologies like Service Worker and Push Notifications.

I would also consider technologies such as Phonegap & Cordova to largely to have been eclipsed by PWAs.

Please keep the above in mind before actively using this plugin.

# Background Service Plugin Core (bgs-core)

## Quick summary
This repository provides the core functionality for the Background Service Plugin for Cordova.  The functionality is not a complete plugin - it is intended to be extended by developers to create their own background service.

An example background service is provided in the https://github.com/Red-Folder/bgs-sample repository.

## Getting started
To understand how to create your own background service it is advised that you read the following articles:

* [Using the MyService Sample] (https://github.com/Red-Folder/bgs-core/wiki/Using-the-MyService-Sample)
* [Build your own Background Service] (https://github.com/Red-Folder/bgs-core/wiki/Build-your-own-Background-Service)
* [Build your own plugin] (https://github.com/Red-Folder/bgs-core/wiki/Build-your-own-plugin)

Further documentation can be found at https://github.com/Red-Folder/bgs-core/wiki

## Questions and Support
If you have problems, then please log an issue against the bgs-core repository (https://github.com/Red-Folder/bgs-core/issues).

As the plugin is updated (for new features or fixes) I will tweet via @FolderRed and blog http://red-folder.blogspot.co.uk/

## Older version
This version of the plugin is intended to work with Cordova 3.0.0+

The older version of the plugin is available at https://github.com/Red-Folder/Cordova-Plugin-BackgroundService.  Please note however that this older repository is unlikely to be maintained going forwards.  It is advised that you move to Cordova 3.x.x as soon as possible.

## Spread the love

If you find the Background Service Plugin useful then spread the love.

All the work I do on the Plugin is done in my spare time - time I would otherwise be spending taking my wife out for a nice meal or helping my lad find vinyl records (he's currently very much into The Smiths, Fleetwood Mac and Kate Bush).

The Plugin is free and will always remain free. I will continue to develop, maintain and distribute the Plugin under the MIT License.

https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=E64TCFQ3NLHZ8

## Licence
Copyright 2013 Red Folder Consultancy Ltd
    
Licensed under the Apache License, Version 2.0 (the "License");   
you may not use this file except in compliance with the License.   
You may obtain a copy of the License at       
  
http://www.apache.org/licenses/LICENSE-2.0   
 
Unless required by applicable law or agreed to in writing, software   
distributed under the License is distributed on an "AS IS" BASIS,   
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   
See the License for the specific language governing permissions and   
limitations under the License.


================================================
FILE: aidl/android/BackgroundServiceApi.aidl
================================================
package com.red_folder.phonegap.plugin.backgroundservice;   

import com.red_folder.phonegap.plugin.backgroundservice.BackgroundServiceListener;

interface BackgroundServiceApi {  
	String getLatestResult();     
	
	void addListener(BackgroundServiceListener listener);     
	
	void removeListener(BackgroundServiceListener listener); 
	
	boolean isTimerEnabled();
	
	void enableTimer(int milliseconds);
	
	void disableTimer();
	
	String getConfiguration();
	
	void setConfiguration(String configuration);
	
	int getTimerMilliseconds();
	
	void run();
} 


================================================
FILE: aidl/android/BackgroundServiceListener.aidl
================================================
package com.red_folder.phonegap.plugin.backgroundservice;   

interface BackgroundServiceListener {     
	void handleUpdate(); 
	String getUniqueID();
} 


================================================
FILE: package.json
================================================
{
  "name": "com.red_folder.phonegap.plugin.backgroundservice",
  "version": "2.0.0",
  "description": "Framework code that allows the development and operation of an Android Background Service.",
  "repository": {
    "type": "git",
    "url": "git+https://github.com/Red-Folder/bgs-core.git"
  },
  "keywords": [
    "background",
    "cordova"
  ],
  "platforms": [
    "android"
  ],
  "engines": [
    {
      "name": "cordova",
      "version": ">=3.0.0"
    }
  ],
  "author": "Red-Folder",
  "license": "Apache 2.0",
  "bugs": {
    "url": "https://github.com/Red-Folder/bgs-core/issues"
  },
  "homepage": "https://github.com/Red-Folder/bgs-core#readme"
}


================================================
FILE: plugin.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<plugin xmlns="http://apache.org/cordova/ns/plugins/1.0"
        xmlns:android="http://schemas.android.com/apk/res/android"
        id="com.red_folder.phonegap.plugin.backgroundservice"
        version="2.0.0"
>

    <engines>
        <engine name="cordova" version=">=3.0.0"/>
    </engines>

    <name>Background Service Plugin - Core logic</name>
    <description>Framework code that allows the development and operation of an Android Background Service.</description>
    <license>Apache 2.0</license>
    <keywords>cordova,background</keywords>
    
    <js-module src="www/backgroundService.js" name="BackgroundService">
    </js-module>

    <platform name="android">

        <config-file target="res/xml/config.xml" parent="/*">
            <feature name="BackgroundServicePlugin">
                 <param name="android-package" value="com.red_folder.phonegap.plugin.backgroundservice.BackgroundServicePlugin"/>
            </feature>
        </config-file>

        <config-file target="AndroidManifest.xml" parent="/manifest">
            <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
        </config-file>

        <config-file target="AndroidManifest.xml" parent="/manifest/application">
  
            <receiver android:name="com.red_folder.phonegap.plugin.backgroundservice.BootReceiver">
                <intent-filter>     
                    <action android:name="android.intent.action.BOOT_COMPLETED"></action>   
                </intent-filter> 
            </receiver>
            
        </config-file>

         <source-file src="src/android/BackgroundService.java" target-dir="src/com/red_folder/phonegap/plugin/backgroundservice" />
        <source-file src="src/android/BackgroundServicePlugin.java" target-dir="src/com/red_folder/phonegap/plugin/backgroundservice" />
        <source-file src="src/android/BackgroundServicePluginLogic.java" target-dir="src/com/red_folder/phonegap/plugin/backgroundservice" />
        <source-file src="src/android/BootReceiver.java" target-dir="src/com/red_folder/phonegap/plugin/backgroundservice" />
        <source-file src="src/android/PropertyHelper.java" target-dir="src/com/red_folder/phonegap/plugin/backgroundservice" />
        <source-file src="src/android/ReflectionHelper.java" target-dir="src/com/red_folder/phonegap/plugin/backgroundservice" />
        
        <source-file src="aidl/android/BackgroundServiceApi.aidl" target-dir="src/com/red_folder/phonegap/plugin/backgroundservice" />
        <source-file src="aidl/android/BackgroundServiceListener.aidl" target-dir="src/com/red_folder/phonegap/plugin/backgroundservice" />

    </platform>
</plugin>


================================================
FILE: src/android/BackgroundService.java
================================================
package com.red_folder.phonegap.plugin.backgroundservice;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Timer;

import java.util.TimerTask;

import org.json.JSONObject;

import android.app.Service;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.IBinder;
import android.os.RemoteException;
import android.preference.PreferenceManager;
import android.util.Log;

import com.red_folder.phonegap.plugin.backgroundservice.BackgroundServiceApi;

public abstract class BackgroundService extends Service {
	
	/*
	 ************************************************************************************************
	 * Static values 
	 ************************************************************************************************
	 */
	private static final String TAG = BackgroundService.class.getSimpleName();

	/*
	 ************************************************************************************************
	 * Fields 
	 ************************************************************************************************
	 */
	private Boolean mServiceInitialised = false;
	private Timer mTimer;
	
	private final Object mResultLock = new Object();
	private JSONObject mLatestResult = null;

	private List<BackgroundServiceListener> mListeners = new ArrayList<BackgroundServiceListener>();
	
	private TimerTask mUpdateTask;
	
	private Date mPausedUntil = null;

	public void setPauseDuration(long pauseDuration) {
		this.mPausedUntil = new Date(new Date().getTime() + pauseDuration);
		
		// Call the onPause event
		onPause();
	}
	
	public Boolean getEnabled() {
		SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);  

		return sharedPrefs.getBoolean(this.getClass().getName() + ".Enabled", false);
	}

	public void setEnabled(Boolean enabled) {
		SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);  

		SharedPreferences.Editor editor = sharedPrefs.edit();
        editor.putBoolean(this.getClass().getName() + ".Enabled", enabled);
        editor.commit(); // Very important
	}
	
	public int getMilliseconds() {
		SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);  

		// Should default to a minute
		return sharedPrefs.getInt(this.getClass().getName() + ".Milliseconds", 60000 );	
	}

	public void setMilliseconds(int milliseconds) {
		SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);  

		SharedPreferences.Editor editor = sharedPrefs.edit();
        editor.putInt(this.getClass().getName() + ".Milliseconds", milliseconds);
        editor.commit(); // Very important
	}

	protected JSONObject getLatestResult() {
		synchronized (mResultLock) {
			return mLatestResult;
		}
	}
	
	protected void setLatestResult(JSONObject value) {
		synchronized (mResultLock) {
			this.mLatestResult = value;
		}
	}

	public void restartTimer() {
        
        // Stop the timertask and restart for the new interval to take effect
        if (this.mUpdateTask != null) {
        	this.mUpdateTask.cancel();
        	this.mUpdateTask = null;

			this.mUpdateTask = getTimerTask(); 			
			this.mTimer.schedule(this.mUpdateTask, getMilliseconds(), getMilliseconds());
        }
	}
	
	/*
	 ************************************************************************************************
	 * Overriden Methods 
	 ************************************************************************************************
	 */

	@Override  
	public IBinder onBind(Intent intent) {
		Log.i(TAG, "onBind called");
		return apiEndpoint;
	}     
	
	@Override
	public int onStartCommand(Intent intent, int flags, int startId) {
	    super.onStartCommand(intent, flags, startId);
	    Log.d(TAG, "onStartCommand run");

	    initialiseService();
	    return START_STICKY;  
	}

	@Override  
	public void onDestroy() {     
		super.onDestroy();     
		Log.i(TAG, "Service destroying");
		
		cleanupService();
	}
	
	/*
	 ************************************************************************************************
	 * Protected methods 
	 ************************************************************************************************
	 */
	protected void runOnce() {
		// Runs the doWork once
		// Sets the last result & updates the listeners
		doWorkWrapper();
	}

	/*
	 ************************************************************************************************
	 * Private methods 
	 ************************************************************************************************
	 */
	private BackgroundServiceApi.Stub apiEndpoint = new BackgroundServiceApi.Stub() {

		/*
		 ************************************************************************************************
		 * Overriden Methods 
		 ************************************************************************************************
		 */
		@Override
		public String getLatestResult() throws RemoteException {
			synchronized (mResultLock) {
				if (mLatestResult == null)
					return "{}";
				else
					return mLatestResult.toString();
			}
		}

		@Override
		public void addListener(BackgroundServiceListener listener)
				throws RemoteException {

			synchronized (mListeners) {
				if (mListeners.add(listener))
					Log.d(TAG, "Listener added");
				else
					Log.d(TAG, "Listener not added");
			}
		}

		@Override
		public void removeListener(BackgroundServiceListener listener)
				throws RemoteException {

			synchronized (mListeners) {
				if (mListeners.size() > 0) {
					boolean removed = false;
					for (int i = 0; i < mListeners.size() && !removed; i++)
					{
						if (listener.getUniqueID().equals(mListeners.get(i).getUniqueID())) {
							mListeners.remove(i);
							removed = true;
						}
					}
					
					if (removed)
						Log.d(TAG, "Listener removed");
					else 
						Log.d(TAG, "Listener not found");
				}
			}
		}

		@Override
		public void enableTimer(int milliseconds) throws RemoteException {
			// First stop it just to be on the safe side
			stopTimerTask();
			
			// Then enable and set the milliseconds
			setEnabled(true);
			setMilliseconds(milliseconds);
			
			// Finally setup the TimerTask
			setupTimerTask();
		}

		@Override
		public void disableTimer() throws RemoteException {
			// Set to disabled
			setEnabled(false);
			
			// Stop the timer task
			stopTimerTask();
		}

		@Override
		public boolean isTimerEnabled() throws RemoteException {
			return getEnabled();
		}

		@Override
		public String getConfiguration() throws RemoteException {
			JSONObject array = getConfig();
			if (array == null)
				return "";
			else 
				return array.toString();
		}

		@Override
		public void setConfiguration(String configuration) throws RemoteException {
			try {
				JSONObject array = null;
				if (configuration.length() > 0) {
					array = new JSONObject(configuration);
				} else {
					array = new JSONObject();
				}	
				setConfig(array);
			} catch (Exception ex) {
				throw new RemoteException();
			}
		}

		@Override
		public int getTimerMilliseconds() throws RemoteException {
			return getMilliseconds();
		}

		@Override
		public void run() throws RemoteException {
			runOnce();
		}
	};

	private void initialiseService() {
		
		if (!this.mServiceInitialised) {
			Log.i(TAG, "Initialising the service");

			// Initialise the LatestResult object
			JSONObject tmp = initialiseLatestResult();

			Log.i(TAG, "Syncing result");
			this.setLatestResult(tmp);
		
			if (getEnabled())
				this.setupTimerTask();
			
			this.mServiceInitialised = true;
		}

	}
	
	private void cleanupService() {
		Log.i(TAG, "Running cleanupService");
		
		Log.i(TAG, "Stopping timer task");
		stopTimerTask();

		Log.i(TAG, "Removing the timer");
		if (this.mTimer != null) {
			Log.i(TAG, "Timer is not null");
			try {
				this.mTimer.cancel();     
				Log.i(TAG, "Timer.cancel has been called");
				this.mTimer = null;
			} catch (Exception ex) {
				Log.i(TAG, "Exception has occurred - " + ex.getMessage());
			}
		}

	}

	private void setupTimerTask () {
		// Only create a timer if the timer is null
		if (this.mTimer == null) {
			this.mTimer = new Timer(this.getClass().getName());
		}
		
		// Only create the updateTask if is null
		if (this.mUpdateTask == null) {
			this.mUpdateTask = getTimerTask(); 			
			int milliseconds = getMilliseconds();
			this.mTimer.schedule(this.mUpdateTask, 1000L, milliseconds);
		}

		onTimerEnabled();
	}
	
	private void stopTimerTask() {
		
		Log.i(TAG, "stopTimerTask called");
		if (this.mUpdateTask != null)
		{
			Log.i(TAG, "updateTask is not null");
			if (this.mUpdateTask.cancel() )
			{
				Log.i(TAG, "updateTask.cancel returned true");
			} else {
				Log.i(TAG, "updateTask.cancel returned false");
			}
			this.mUpdateTask = null;
		}
		
		onTimerDisabled();
	}
	
	private TimerTask getTimerTask() {
		return new TimerTask() {

			@Override    
			public void run() {       
				Log.i(TAG, "Timer task starting work");

				Log.d(TAG, "Is the service paused?");
				Boolean paused = false;
				if (mPausedUntil != null) {
					Log.d(TAG, "Service is paused until " + (new SimpleDateFormat("dd/MM/yyyy hh:mm:ss")).format(mPausedUntil));
					Date current = new Date();
					Log.d(TAG, "Current is " + (new SimpleDateFormat("dd/MM/yyyy hh:mm:ss")).format(current));
					if (mPausedUntil.after(current)) {
						Log.d(TAG, "Service should be paused");
						paused = true;					// Still paused
					} else {
						Log.d(TAG, "Service should not be paused");
						mPausedUntil = null;				// Paused time has past so we can clear the pause
						onPauseComplete();
					}
				}

				if (paused) {
					Log.d(TAG, "Service is paused");
				} else {
					Log.d(TAG, "Service is not paused");
					
					// Runs the doWork 
					// Sets the last result & updates the listeners
					doWorkWrapper();
				}

				Log.i(TAG, "Timer task completing work");
			}   
		};

	}
	
	// Seperated out to allow the doWork to be called from timer and adhoc (via run method)
	private void doWorkWrapper() {
		JSONObject tmp = null;
		
		try {
			tmp = doWork();
		} catch (Exception ex) {
			Log.i(TAG, "Exception occurred during doWork()", ex);
		}

		Log.i(TAG, "Syncing result");
		setLatestResult(tmp);
		
		// Now call the listeners
		Log.i(TAG, "Sending to all listeners");
		for (int i = 0; i < mListeners.size(); i++)
		{
			try {
				mListeners.get(i).handleUpdate();
				Log.i(TAG, "Sent listener - " + i);
			} catch (RemoteException e) {
				Log.i(TAG, "Failed to send to listener - " + i + " - " + e.getMessage());
			}
		}
		
	}
	
	/*
	 ************************************************************************************************
	 * Methods for subclasses to override 
	 ************************************************************************************************
	 */
	protected abstract JSONObject initialiseLatestResult(); 
	protected abstract JSONObject doWork();
	protected abstract JSONObject getConfig();
	protected abstract void setConfig(JSONObject config);
	
	protected void onTimerEnabled() {
	}

	protected void onTimerDisabled() {
	}
	
	protected void onPause() {
	}
	
	protected void onPauseComplete() {
	}
}


================================================
FILE: src/android/BackgroundServicePlugin.java
================================================
package com.red_folder.phonegap.plugin.backgroundservice;

import org.apache.cordova.CallbackContext;
import org.apache.cordova.PluginResult;
import org.json.JSONArray;

import android.util.Log;

import org.apache.cordova.CordovaPlugin;

import com.red_folder.phonegap.plugin.backgroundservice.BackgroundServicePluginLogic.ExecuteResult;
import com.red_folder.phonegap.plugin.backgroundservice.BackgroundServicePluginLogic.ExecuteStatus;

public class BackgroundServicePlugin extends CordovaPlugin implements BackgroundServicePluginLogic.IUpdateListener {

	/*
	 ************************************************************************************************
	 * Static values 
	 ************************************************************************************************
	 */
	private static final String TAG = BackgroundServicePlugin.class.getSimpleName();

	/*
	 ************************************************************************************************
	 * Fields 
	 ************************************************************************************************
	 */
	// Part fix for https://github.com/Red-Folder/Cordova-Plugin-BackgroundService/issues/19
	//private final BackgroundServicePluginLogic mLogic = new BackgroundServicePluginLogic();
	private BackgroundServicePluginLogic mLogic = null;

	/*
	 ************************************************************************************************
	 * Overriden Methods 
	 ************************************************************************************************
	 */
	// Part fix for https://github.com/Red-Folder/Cordova-Plugin-BackgroundService/issues/19
	//public boolean execute(String action, JSONArray data, CallbackContext callback) {
	@Override
	public boolean execute(final String action, final JSONArray data, final CallbackContext callback) {
	
	
		boolean result = false;
		
		
		if (this.mLogic == null)
			this.mLogic = new BackgroundServicePluginLogic(this.cordova.getActivity());
		
		// Part fix for https://github.com/Red-Folder/Cordova-Plugin-BackgroundService/issues/19
		//if (this.mLogic.isInitialized())
		//	this.mLogic.initialize(this.cordova.getActivity());
		
		try {
			
			if (this.mLogic.isActionValid(action)) {
				
				//Part fix for https://github.com/Red-Folder/Cordova-Plugin-BackgroundService/issues/19
				//final String finalAction = action;
				//final JSONArray finalData = data;
				//final CallbackContext finalCallback = callback;

				final BackgroundServicePluginLogic.IUpdateListener listener = this;
				final Object[] listenerExtras = new Object[] { callback };
			
				cordova.getThreadPool().execute(new Runnable() {
					@Override
					public void run() {
						ExecuteResult logicResult = mLogic.execute(action, data, listener, listenerExtras);

						Log.d(TAG, "logicResult = " +  logicResult.toString());
						
						PluginResult pluginResult = transformResult(logicResult);
												
						Log.d(TAG, "pluginResult = " +  pluginResult.toString());
						Log.d(TAG, "pluginResult.getMessage() = " +  pluginResult.getMessage());
						if (pluginResult.getKeepCallback())
							Log.d(TAG, "Keep Callback");
						else
							Log.d(TAG, "Dont keep Callback");
						
						callback.sendPluginResult(pluginResult);
					}
				});

				result = true;
			} else {
				result = false;
			}
			
		} catch (Exception ex) {
			Log.d(TAG, "Exception - " + ex.getMessage());
		}

		return result;
	}

	@Override
	public void onDestroy() {
		super.onDestroy();

		if (this.mLogic != null) {
			this.mLogic.onDestroy();
			this.mLogic = null;
		}
	}

	/*
	 ************************************************************************************************
	 * Public Methods 
	 ************************************************************************************************
	 */
	public void handleUpdate(ExecuteResult logicResult, Object[] listenerExtras) {
		Log.d(TAG, "Starting handleUpdate");
		sendUpdateToListener(logicResult, listenerExtras);
		Log.d(TAG, "Finished handleUpdate");
	}
	
	public void closeListener(ExecuteResult logicResult, Object[] listenerExtras) {
		Log.d(TAG, "Starting closeListener");
		sendUpdateToListener(logicResult, listenerExtras);
		Log.d(TAG, "Finished closeListener");
	}

	/*
	 ************************************************************************************************
	 * Private Methods 
	 ************************************************************************************************
	 */
	private void sendUpdateToListener(ExecuteResult logicResult, Object[] listenerExtras) {
		try {
			if (listenerExtras != null && listenerExtras.length > 0) {
				Log.d(TAG, "Sending update");
				CallbackContext callback = (CallbackContext)listenerExtras[0];
		
				callback.sendPluginResult(transformResult(logicResult));
				Log.d(TAG, "Sent update");
			}
		} catch (Exception ex) {
			Log.d(TAG, "Sending update failed", ex);
		}
	}
	
	private PluginResult transformResult(ExecuteResult logicResult) {
		PluginResult pluginResult = null;
		
		Log.d(TAG, "Start of transformResult");
		if (logicResult.getStatus() == ExecuteStatus.OK) {
			Log.d(TAG, "Status is OK");
			
			if (logicResult.getData() == null) {
				Log.d(TAG, "We dont have data");
				pluginResult = new PluginResult(PluginResult.Status.OK);
			} else {
				Log.d(TAG, "We have data");
				pluginResult = new PluginResult(PluginResult.Status.OK, logicResult.getData());
			}
		}

		if (logicResult.getStatus() == ExecuteStatus.ERROR) {
			Log.d(TAG, "Status is ERROR");
			
			if (logicResult.getData() == null) {
				Log.d(TAG, "We dont have data");
				pluginResult = new PluginResult(PluginResult.Status.ERROR, "Unknown error");
			} else {
				Log.d(TAG, "We have data");
				pluginResult = new PluginResult(PluginResult.Status.ERROR, logicResult.getData());
			}
		}
		
		if (logicResult.getStatus() == ExecuteStatus.INVALID_ACTION) {
			Log.d(TAG, "Status is INVALID_ACTION");
			
			if (logicResult.getData() == null) {
				Log.d(TAG, "We have data");
				pluginResult = new PluginResult(PluginResult.Status.INVALID_ACTION, "Unknown error");
			} else {
				Log.d(TAG, "We dont have data");
				pluginResult = new PluginResult(PluginResult.Status.INVALID_ACTION, logicResult.getData());
			}
		}
		
		if (!logicResult.isFinished()) {
			Log.d(TAG, "Keep Callback set to true");
			pluginResult.setKeepCallback(true);
		}
		
		Log.d(TAG, "End of transformResult");
		return pluginResult;
	}
}


================================================
FILE: src/android/BackgroundServicePluginLogic.java
================================================
package com.red_folder.phonegap.plugin.backgroundservice;

import java.util.Enumeration;
import java.util.Hashtable;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.app.ActivityManager;
import android.app.ActivityManager.RunningServiceInfo;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import android.content.ServiceConnection;

public class BackgroundServicePluginLogic {

	/*
	 ************************************************************************************************
	 * Static values 
	 ************************************************************************************************
	 */
	public static final String TAG = BackgroundServicePluginLogic.class.getSimpleName();
	
	/*
	 ************************************************************************************************
	 * Keys 
	 ************************************************************************************************
	 */
	public static final String ACTION_START_SERVICE = "startService";
	public static final String ACTION_STOP_SERVICE = "stopService";
	
	public static final String ACTION_ENABLE_TIMER = "enableTimer";
	public static final String ACTION_DISABLE_TIMER = "disableTimer";

	public static final String ACTION_SET_CONFIGURATION = "setConfiguration";
	
	public static final String ACTION_REGISTER_FOR_BOOTSTART = "registerForBootStart";
	public static final String ACTION_DEREGISTER_FOR_BOOTSTART = "deregisterForBootStart";
	
	public static final String ACTION_GET_STATUS = "getStatus";

	public static final String ACTION_RUN_ONCE = "runOnce";

	public static final String ACTION_REGISTER_FOR_UPDATES = "registerForUpdates";
	public static final String ACTION_DEREGISTER_FOR_UPDATES = "deregisterForUpdates";
	
	
	public static final int ERROR_NONE_CODE = 0;
	public static final String ERROR_NONE_MSG = "";
	
	public static final int ERROR_PLUGIN_ACTION_NOT_SUPPORTED_CODE = -1;
	public static final String ERROR_PLUGIN_ACTION_NOT_SUPPORTED_MSG = "Passed action not supported by Plugin";
	
	public static final int ERROR_INIT_NOT_YET_CALLED_CODE = -2;
	public static final String ERROR_INIT_NOT_YET_CALLED_MSG = "Please call init prior any other action";
	
	public static final int ERROR_SERVICE_NOT_RUNNING_CODE = -3;
	public static final String ERROR_SERVICE_NOT_RUNNING_MSG = "Sevice not currently running";
	
	public static final int ERROR_UNABLE_TO_BIND_TO_BACKGROUND_SERVICE_CODE = -4;
	public static final String ERROR_UNABLE_TO_BIND_TO_BACKGROUND_SERVICE_MSG ="Plugin unable to bind to background service";
	
	public static final int ERROR_UNABLE_TO_RETRIEVE_LAST_RESULT_CODE = -5;
	public static final String ERROR_UNABLE_TO_RETRIEVE_LAST_RESULT_MSG = "Unable to retrieve latest result (reason unknown)";
	
	public static final int ERROR_LISTENER_ALREADY_REGISTERED_CODE = -6;
	public static final String ERROR_LISTENER_ALREADY_REGISTERED_MSG = "Listener already registered";
	
	public static final int ERROR_LISTENER_NOT_REGISTERED_CODE = -7;
	public static final String ERROR_LISTENER_NOT_REGISTERED_MSG = "Listener not registered";

	public static final int ERROR_UNABLE_TO_CLOSED_LISTENER_CODE = -8;
	public static final String ERROR_UNABLE_TO_CLOSED_LISTENER_MSG = "Unable to close listener";
	
	public static final int ERROR_ACTION_NOT_SUPPORTED__IN_PLUGIN_VERSION_CODE = -9;
	public static final String ERROR_ACTION_NOT_SUPPORTED__IN_PLUGIN_VERSION_MSG = "Action is not supported in this version of the plugin";

	public static final int ERROR_EXCEPTION_CODE = -99;
	
	/*
	 ************************************************************************************************
	 * Fields 
	 ************************************************************************************************
	 */
	private Context mContext;
	private Hashtable<String, ServiceDetails> mServices = new Hashtable<String, ServiceDetails>();

	/*
	 ************************************************************************************************
	 * Constructors 
	 ************************************************************************************************
	 */
	// Part fix for https://github.com/Red-Folder/Cordova-Plugin-BackgroundService/issues/19
	//public BackgroundServicePluginLogic() {
	//}

	public BackgroundServicePluginLogic(Context pContext) {
		this.mContext = pContext;
	}

	/*
	 ************************************************************************************************
	 * Public Methods 
	 ************************************************************************************************
	 */
	
	// Part fix for https://github.com/Red-Folder/Cordova-Plugin-BackgroundService/issues/19
	//public void initialize(Context pContext) {
	//	this.mContext = pContext;
	//}
	
	//public boolean isInitialized() {
	//	if (this.mContext == null)
	//		return false;
	//	else
	//		return true;
	//}
	
	public boolean isActionValid(String action) {
		boolean result = false;

		if(ACTION_START_SERVICE.equals(action)) result = true;
		if(ACTION_STOP_SERVICE.equals(action)) result = true;
		
		if(ACTION_ENABLE_TIMER.equals(action)) result = true;
		if(ACTION_DISABLE_TIMER.equals(action)) result = true;

		if(ACTION_SET_CONFIGURATION.equals(action)) result = true;
		
		if(ACTION_REGISTER_FOR_BOOTSTART.equals(action)) result = true;
		if(ACTION_DEREGISTER_FOR_BOOTSTART.equals(action)) result = true;
		
		if(ACTION_GET_STATUS.equals(action)) result = true;

		if(ACTION_RUN_ONCE.equals(action)) result = true;
		
		if(ACTION_REGISTER_FOR_UPDATES.equals(action)) result = true;
		if(ACTION_DEREGISTER_FOR_UPDATES.equals(action)) result = true;

		return result;
	}

	public ExecuteResult execute(String action, JSONArray data) {
		return execute(action, data, null, null);
	}

	public ExecuteResult execute(String action, JSONArray data, IUpdateListener listener, Object[] listenerExtras) {
		ExecuteResult result = null;
		
		Log.d(TAG, "Start of Execute");
		try {
			Log.d(TAG, "Withing try block");
			if ((data != null) &&
					(!data.isNull(0)) &&
					(data.get(0) instanceof String) &&
					(data.getString(0).length() > 0)) {

				String serviceName = data.getString(0);
				
				Log.d(TAG, "Finding servicename " + serviceName);
				
				ServiceDetails service = null;

				Log.d(TAG, "Services contain " + this.mServices.size() + " records");
				
				if (this.mServices.containsKey(serviceName)) {
					Log.d(TAG, "Found existing Service Details");
					service = this.mServices.get(serviceName);
				} else {
					Log.d(TAG, "Creating new Service Details");
					service = new ServiceDetails(this.mContext, serviceName);
					this.mServices.put(serviceName, service);
				}

				Log.d(TAG, "Action = " + action);


				if (!service.isInitialised())
					service.initialise();

				if (ACTION_GET_STATUS.equals(action)) result = service.getStatus();
				
				if (ACTION_START_SERVICE.equals(action)) result = service.startService();

				if (ACTION_REGISTER_FOR_BOOTSTART.equals(action)) result = service.registerForBootStart();
				if (ACTION_DEREGISTER_FOR_BOOTSTART.equals(action)) result = service.deregisterForBootStart();

				if (ACTION_REGISTER_FOR_UPDATES.equals(action)) result = service.registerForUpdates(listener, listenerExtras);
				if (ACTION_DEREGISTER_FOR_UPDATES.equals(action)) result = service.deregisterForUpdates();

				if (result == null) {
					Log.d(TAG, "Check if the service is running?");

					if (service != null && service.isServiceRunning()) {
						Log.d(TAG, "Service is running?");
						
						if (ACTION_STOP_SERVICE.equals(action)) result = service.stopService();

						if (ACTION_ENABLE_TIMER.equals(action)) result = service.enableTimer(data);
						if (ACTION_DISABLE_TIMER.equals(action)) result = service.disableTimer();

						if (ACTION_SET_CONFIGURATION.equals(action)) result = service.setConfiguration(data);

						if (ACTION_RUN_ONCE.equals(action)) result = service.runOnce();

					} else {
						result = new ExecuteResult(ExecuteStatus.INVALID_ACTION);
					}
				}

				if (result == null)
					result = new ExecuteResult(ExecuteStatus.INVALID_ACTION);
			} else {
				result = new ExecuteResult(ExecuteStatus.ERROR);
				Log.d(TAG, "ERROR - no servicename");
			}
		} catch (Exception ex) {
			result = new ExecuteResult(ExecuteStatus.ERROR);
			Log.d(TAG, "Exception - " + ex.getMessage());
		}

		return result;
	}

	public void onDestroy() {
		
		Log.d(TAG, "On Destroy Start");
		try {
			Log.d(TAG, "Checking for services");
			if (this.mServices != null && 
				this.mServices.size() > 0 ) {

				Log.d(TAG, "Found services");

				Enumeration<String> keys = this.mServices.keys();
				
				while( keys.hasMoreElements() ) {
					String key = keys.nextElement();  
					ServiceDetails service = this.mServices.get(key);
					Log.d(TAG, "Calling service.close()");
					service.close();
				}
			}
		} catch (Throwable t) {
			// catch any issues, typical for destroy routines
			// even if we failed to destroy something, we need to continue destroying
			Log.d(TAG, "Error has occurred while trying to close services", t);
		}
		
		
		this.mServices = null;
		Log.d(TAG, "On Destroy Finish");
		
	}


	/*
	 ************************************************************************************************
	 * Internal Class 
	 ************************************************************************************************
	 */
	protected class ServiceDetails {
		/*
		 ************************************************************************************************
		 * Static values 
		 ************************************************************************************************
		 */
		public final String LOCALTAG = BackgroundServicePluginLogic.ServiceDetails.class.getSimpleName();
		
		/*
		 ************************************************************************************************
		 * Fields 
		 ************************************************************************************************
		 */
		private String mServiceName = "";
		private Context mContext;
		
		private BackgroundServiceApi mApi;

		private String mUniqueID = java.util.UUID.randomUUID().toString();
		
		private boolean mInitialised = false;
		
		private Intent mService = null;
		
		private Object mServiceConnectedLock = new Object();
		private Boolean mServiceConnected = null;

		private IUpdateListener mListener = null;
		private Object[] mListenerExtras = null;
				
		/*
		 ************************************************************************************************
		 * Constructors 
		 ************************************************************************************************
		 */
		public ServiceDetails(Context context, String serviceName)
		{
			this.mContext = context;
			this.mServiceName = serviceName;
		}
		
		/*
		 ************************************************************************************************
		 * Public Methods 
		 ************************************************************************************************
		 */
		public void initialise()
		{
			this.mInitialised = true;
			
			// If the service is running, then automatically bind to it
			if (this.isServiceRunning()) {
				startService();
			}
		}
		
		public boolean isInitialised()
		{
			return mInitialised;
		}

		public ExecuteResult startService()
		{
			Log.d(LOCALTAG, "Starting startService");
			ExecuteResult result = null;
			
			try {
				Log.d(LOCALTAG, "Attempting to bind to Service");
				if (this.bindToService()) {
					Log.d(LOCALTAG, "Bind worked");
					result = new ExecuteResult(ExecuteStatus.OK, createJSONResult(true, ERROR_NONE_CODE, ERROR_NONE_MSG));
				} else {
					Log.d(LOCALTAG, "Bind Failed");
					result = new ExecuteResult(ExecuteStatus.ERROR, createJSONResult(false, ERROR_UNABLE_TO_BIND_TO_BACKGROUND_SERVICE_CODE, ERROR_UNABLE_TO_BIND_TO_BACKGROUND_SERVICE_MSG));
				}
			} catch (Exception ex) {
				Log.d(LOCALTAG, "startService failed", ex);
				result = new ExecuteResult(ExecuteStatus.ERROR, createJSONResult(false, ERROR_EXCEPTION_CODE, ex.getMessage()));
			}
			
			Log.d(LOCALTAG, "Finished startService");
			return result;
		}
		
		public ExecuteResult stopService()
		{
			ExecuteResult result = null;
			
			Log.d("ServiceDetails", "stopService called");

			try {
				
				Log.d("ServiceDetails", "Unbinding Service");
				this.mContext.unbindService(serviceConnection);
				
				Log.d("ServiceDetails", "Stopping service");
				if (this.mContext.stopService(this.mService))
				{
					Log.d("ServiceDetails", "Service stopped");
				} else {
					Log.d("ServiceDetails", "Service not stopped");
				}
				result = new ExecuteResult(ExecuteStatus.OK, createJSONResult(true, ERROR_NONE_CODE, ERROR_NONE_MSG));
			} catch (Exception ex) {
				Log.d(LOCALTAG, "stopService failed", ex);
				result = new ExecuteResult(ExecuteStatus.ERROR, createJSONResult(false, ERROR_EXCEPTION_CODE, ex.getMessage()));
			}
			
			return result;
		}
		
		public ExecuteResult enableTimer(JSONArray data)
		{
			ExecuteResult result = null;

			int milliseconds = data.optInt(1, 60000);
			try {
				mApi.enableTimer(milliseconds);
				result = new ExecuteResult(ExecuteStatus.OK, createJSONResult(true, ERROR_NONE_CODE, ERROR_NONE_MSG));
			} catch (RemoteException ex) {
				Log.d(LOCALTAG, "enableTimer failed", ex);
				result = new ExecuteResult(ExecuteStatus.ERROR, createJSONResult(false, ERROR_EXCEPTION_CODE, ex.getMessage()));
			}

			return result;
		}

		public ExecuteResult disableTimer()
		{
			ExecuteResult result = null;
		
			try {
				mApi.disableTimer();
				result = new ExecuteResult(ExecuteStatus.OK, createJSONResult(true, ERROR_NONE_CODE, ERROR_NONE_MSG));
			} catch (RemoteException ex) {
				Log.d(LOCALTAG, "disableTimer failed", ex);
				result = new ExecuteResult(ExecuteStatus.ERROR, createJSONResult(false, ERROR_EXCEPTION_CODE, ex.getMessage()));
			}

			return result;
		}

		public ExecuteResult registerForBootStart()
		{
			ExecuteResult result = null;
		
			try {
				PropertyHelper.addBootService(this.mContext, this.mServiceName);

				result = new ExecuteResult(ExecuteStatus.OK, createJSONResult(true, ERROR_NONE_CODE, ERROR_NONE_MSG));
			} catch (Exception ex) {
				Log.d(LOCALTAG, "registerForBootStart failed", ex);
				result = new ExecuteResult(ExecuteStatus.ERROR, createJSONResult(false, ERROR_EXCEPTION_CODE, ex.getMessage()));
			}

			return result;
		}
		
		public ExecuteResult deregisterForBootStart()
		{
			ExecuteResult result = null;
		
			try {
				PropertyHelper.removeBootService(this.mContext, this.mServiceName);

				result = new ExecuteResult(ExecuteStatus.OK, createJSONResult(true, ERROR_NONE_CODE, ERROR_NONE_MSG));
			} catch (Exception ex) {
				Log.d(LOCALTAG, "deregisterForBootStart failed", ex);
				result = new ExecuteResult(ExecuteStatus.ERROR, createJSONResult(false, ERROR_EXCEPTION_CODE, ex.getMessage()));
			}

			return result;
		}
		
		public ExecuteResult setConfiguration(JSONArray data)
		{
			ExecuteResult result = null;
			
			try {
				if (this.isServiceRunning()) {
					Object obj;
					try {
						obj = data.get(1);
						mApi.setConfiguration(obj.toString());
						result = new ExecuteResult(ExecuteStatus.OK, createJSONResult(true, ERROR_NONE_CODE, ERROR_NONE_MSG));
					} catch (JSONException e) {
						Log.d(LOCALTAG, "Processing config JSON from background service failed", e);
						result = new ExecuteResult(ExecuteStatus.ERROR, createJSONResult(false, ERROR_EXCEPTION_CODE, e.getMessage()));
					}
				} else {
					result = new ExecuteResult(ExecuteStatus.INVALID_ACTION, createJSONResult(false, ERROR_SERVICE_NOT_RUNNING_CODE, ERROR_SERVICE_NOT_RUNNING_MSG));
				}
			} catch (RemoteException ex) {
				Log.d(LOCALTAG, "setConfiguration failed", ex);
				result = new ExecuteResult(ExecuteStatus.ERROR, createJSONResult(false, ERROR_EXCEPTION_CODE, ex.getMessage()));
			}
			
			return result;
		}

		public ExecuteResult getStatus()
		{
			ExecuteResult result = null;
			
			result = new ExecuteResult(ExecuteStatus.OK, createJSONResult(true, ERROR_NONE_CODE, ERROR_NONE_MSG));
			
			return result;
		}
		
		public ExecuteResult runOnce()
		{
			ExecuteResult result = null;
			
			try {
				if (this.isServiceRunning()) {
					mApi.run();
					result = new ExecuteResult(ExecuteStatus.OK, createJSONResult(true, ERROR_NONE_CODE, ERROR_NONE_MSG));
				} else {
					result = new ExecuteResult(ExecuteStatus.INVALID_ACTION, createJSONResult(false, ERROR_SERVICE_NOT_RUNNING_CODE, ERROR_SERVICE_NOT_RUNNING_MSG));
				}
			} catch (RemoteException ex) {
				Log.d(LOCALTAG, "runOnce failed", ex);
				result = new ExecuteResult(ExecuteStatus.ERROR, createJSONResult(false, ERROR_EXCEPTION_CODE, ex.getMessage()));
			}
			
			return result;
		}

		public ExecuteResult registerForUpdates(IUpdateListener listener, Object[] listenerExtras)
		{
			ExecuteResult result = null;
			try {
				
				// Check for if the listener is null
				// If it is then it will be because the Plguin version doesn't support the method
				if (listener == null) {
					result = new ExecuteResult(ExecuteStatus.INVALID_ACTION, createJSONResult(false, ERROR_ACTION_NOT_SUPPORTED__IN_PLUGIN_VERSION_CODE, ERROR_ACTION_NOT_SUPPORTED__IN_PLUGIN_VERSION_MSG));
				} else {
					
					// If a listener already exists, then we fist need to deregister the original
					// Ignore any failures (likely due to the listener not being available anymore)
					if (this.isRegisteredForUpdates()) 
						this.deregisterListener();
				
					this.mListener = listener;
					this.mListenerExtras = listenerExtras;

					result = new ExecuteResult(ExecuteStatus.OK, createJSONResult(true, ERROR_NONE_CODE, ERROR_NONE_MSG), false);
				}
			} catch (Exception ex) {
				Log.d(LOCALTAG, "regsiterForUpdates failed", ex);
				result = new ExecuteResult(ExecuteStatus.ERROR, createJSONResult(false, ERROR_EXCEPTION_CODE, ex.getMessage()));
			}
			
			return result;
		}
		
		public ExecuteResult deregisterForUpdates()
		{
			ExecuteResult result = null;
			try {
				if (this.isRegisteredForUpdates())
					if (this.deregisterListener())
						result = new ExecuteResult(ExecuteStatus.OK, createJSONResult(true, ERROR_NONE_CODE, ERROR_NONE_MSG));
					else
						result = new ExecuteResult(ExecuteStatus.ERROR, createJSONResult(false, ERROR_UNABLE_TO_CLOSED_LISTENER_CODE, ERROR_UNABLE_TO_CLOSED_LISTENER_MSG));
				else
					result = new ExecuteResult(ExecuteStatus.INVALID_ACTION, createJSONResult(false, ERROR_LISTENER_NOT_REGISTERED_CODE, ERROR_LISTENER_NOT_REGISTERED_MSG));
				
			} catch (Exception ex) {
				Log.d(LOCALTAG, "deregsiterForUpdates failed", ex);
				result = new ExecuteResult(ExecuteStatus.ERROR, createJSONResult(false, ERROR_EXCEPTION_CODE, ex.getMessage()));
			}
			
			return result;
		}

		/*
		 * Background Service specific methods
		 */
		public void close()
		{
			Log.d("ServiceDetails", "Close called");
			try {
				// Remove the lister to this publisher
				this.deregisterListener();
				
				Log.d("ServiceDetails", "Removing ServiceListener");
				mApi.removeListener(serviceListener);
				Log.d("ServiceDetails", "Removing ServiceConnection");
				this.mContext.unbindService(serviceConnection);
			} catch (Exception ex) {
				// catch any issues, typical for destroy routines
				// even if we failed to destroy something, we need to continue destroying
				Log.d(LOCALTAG, "close failed", ex);
				Log.d(LOCALTAG, "Ignoring exception - will continue");
			}
			Log.d("ServiceDetails", "Close finished");
		}

		private boolean deregisterListener() {
			boolean result = false;

			if (this.isRegisteredForUpdates()) {
				Log.d("ServiceDetails", "Listener deregistering");
				try {
					Log.d("ServiceDetails", "Listener closing");
					this.mListener.closeListener(new ExecuteResult(ExecuteStatus.OK, createJSONResult(true, ERROR_NONE_CODE, ERROR_NONE_MSG)), this.mListenerExtras);
					Log.d("ServiceDetails", "Listener closed");
				} catch (Exception ex) {
					Log.d("ServiceDetails", "Error occurred while closing the listener", ex);
				}
				
				this.mListener = null;
				this.mListenerExtras = null;
				Log.d("ServiceDetails", "Listener deregistered");
				
				result = true;
			}
			
			return result;
		}

		/*
		 ************************************************************************************************
		 * Private Methods 
		 ************************************************************************************************
		 */
		private boolean bindToService() {
			boolean result = false;
			
			Log.d(LOCALTAG, "Starting bindToService");
			
			try {
				// Fix to https://github.com/Red-Folder/bgs-core/issues/18
				// Gets the class from string
				Class<?> serviceClass = ReflectionHelper.LoadClass(this.mServiceName);
				this.mService = new Intent(this.mContext, serviceClass);

				Log.d(LOCALTAG, "Attempting to start service");
				this.mContext.startService(this.mService);

				Log.d(LOCALTAG, "Attempting to bind to service");
				if (this.mContext.bindService(this.mService, serviceConnection, 0)) {
					Log.d(LOCALTAG, "Waiting for service connected lock");
					synchronized(mServiceConnectedLock) {
						while (mServiceConnected==null) {
							try {
								mServiceConnectedLock.wait();
							} catch (InterruptedException e) {
								Log.d(LOCALTAG, "Interrupt occurred while waiting for connection", e);
							}
						}
						result = this.mServiceConnected;
					}
				}
			} catch (Exception ex) {
				Log.d(LOCALTAG, "bindToService failed", ex);
			}

			Log.d(LOCALTAG, "Finished bindToService");

			return result;
		}
		
		private ServiceConnection serviceConnection = new ServiceConnection() {
			@Override
			public void onServiceConnected(ComponentName name, IBinder service) {
				// that's how we get the client side of the IPC connection
				mApi = BackgroundServiceApi.Stub.asInterface(service);
				try {
					mApi.addListener(serviceListener);
				} catch (RemoteException e) {
					Log.d(LOCALTAG, "addListener failed", e);
				}
				
				synchronized(mServiceConnectedLock) {
					mServiceConnected = true;

					mServiceConnectedLock.notify();
				}

			}

			@Override
			public void onServiceDisconnected(ComponentName name) {
				synchronized(mServiceConnectedLock) {
					mServiceConnected = false;

					mServiceConnectedLock.notify();
				}
			}
		};

		private BackgroundServiceListener.Stub serviceListener = new BackgroundServiceListener.Stub() {
			@Override
			public void handleUpdate() throws RemoteException {
				handleLatestResult();
			}

			@Override
			public String getUniqueID() throws RemoteException {
				return mUniqueID;
			}
		};

		private void handleLatestResult() {
			Log.d("ServiceDetails", "Latest results received");
			
			if (this.isRegisteredForUpdates()) {
				Log.d("ServiceDetails", "Calling listener");
				
				ExecuteResult result = new ExecuteResult(ExecuteStatus.OK, createJSONResult(true, ERROR_NONE_CODE, ERROR_NONE_MSG), false);
				try {
					this.mListener.handleUpdate(result, this.mListenerExtras);
					Log.d("ServiceDetails", "Listener finished");
				} catch (Exception ex) {
					Log.d("ServiceDetails", "Listener failed", ex);
					Log.d("ServiceDetails", "Disabling listener");
					this.mListener = null;
					this.mListenerExtras = null;
				}
			} else {
				Log.d("ServiceDetails", "No action performed");
			}
		}

		private JSONObject createJSONResult(Boolean success, int errorCode, String errorMessage) {
			JSONObject result = new JSONObject();

			// Append the basic information
			try {
				result.put("Success", success);
				result.put("ErrorCode", errorCode);
				result.put("ErrorMessage", errorMessage);
			} catch (JSONException e) {
				Log.d(LOCALTAG, "Adding basic info to JSONObject failed", e);
			}

			if (this.mServiceConnected != null && this.mServiceConnected && this.isServiceRunning()) {
				try { result.put("ServiceRunning", true); } catch (Exception ex) {Log.d(LOCALTAG, "Adding ServiceRunning to JSONObject failed", ex);};
				try { result.put("TimerEnabled", isTimerEnabled()); } catch (Exception ex) {Log.d(LOCALTAG, "Adding TimerEnabled to JSONObject failed", ex);};
				try { result.put("Configuration", getConfiguration()); } catch (Exception ex) {Log.d(LOCALTAG, "Adding Configuration to JSONObject failed", ex);};
				try { result.put("LatestResult", getLatestResult()); } catch (Exception ex) {Log.d(LOCALTAG, "Adding LatestResult to JSONObject failed", ex);};
				try { result.put("TimerMilliseconds", getTimerMilliseconds()); } catch (Exception ex) {Log.d(LOCALTAG, "Adding TimerMilliseconds to JSONObject failed", ex);};
			} else {
				try { result.put("ServiceRunning", false); } catch (Exception ex) {Log.d(LOCALTAG, "Adding ServiceRunning to JSONObject failed", ex);};
				try { result.put("TimerEnabled", JSONObject.NULL); } catch (Exception ex) {Log.d(LOCALTAG, "Adding TimerEnabled to JSONObject failed", ex);};
				try { result.put("Configuration", JSONObject.NULL); } catch (Exception ex) {Log.d(LOCALTAG, "Adding Configuration to JSONObject failed", ex);};
				try { result.put("LatestResult", JSONObject.NULL); } catch (Exception ex) {Log.d(LOCALTAG, "Adding LatestResult to JSONObject failed", ex);};
				try { result.put("TimerMilliseconds", JSONObject.NULL); } catch (Exception ex) {Log.d(LOCALTAG, "Adding TimerMilliseconds to JSONObject failed", ex);};
			}

			try { result.put("RegisteredForBootStart", isRegisteredForBootStart()); } catch (Exception ex) {Log.d(LOCALTAG, "Adding RegisteredForBootStart to JSONObject failed", ex);};
			try { result.put("RegisteredForUpdates", isRegisteredForUpdates()); } catch (Exception ex) {Log.d(LOCALTAG, "Adding RegisteredForUpdates to JSONObject failed", ex);};
				
			return result;
		}
		
		private boolean isServiceRunning()
		{
			boolean result = false;
			
			try {
				// Return Plugin with ServiceRunning true/ false
				ActivityManager manager = (ActivityManager)this.mContext.getSystemService(Context.ACTIVITY_SERVICE); 
				for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) { 
					if (this.mServiceName.equals(service.service.getClassName())) { 
						result = true; 
					} 
				} 
			} catch (Exception ex) {
				Log.d(LOCALTAG, "isServiceRunning failed", ex);
			}

		    return result;
		}

		private Boolean isTimerEnabled()
		{
			Boolean result = false;
			
			try {
				result = mApi.isTimerEnabled();
			} catch (Exception ex) {
				Log.d(LOCALTAG, "isTimerEnabled failed", ex);
			}
			
			return result;
		}

		private Boolean isRegisteredForBootStart()
		{
			Boolean result = false;
		
			try {
				result = PropertyHelper.isBootService(this.mContext, this.mServiceName);
			} catch (Exception ex) {
				Log.d(LOCALTAG, "isRegisteredForBootStart failed", ex);
			}

			return result;
		}

		private Boolean isRegisteredForUpdates()
		{
			if (this.mListener == null)
				return false;
			else
				return true;
		}

		private JSONObject getConfiguration()
		{
			JSONObject result = null;
			
			try {
				String data = mApi.getConfiguration();
				result = new JSONObject(data);
			} catch (Exception ex) {
				Log.d(LOCALTAG, "getConfiguration failed", ex);
			}
			
			return result;
		}

		private JSONObject getLatestResult()
		{
			JSONObject result = null;

			try {
				String data = mApi.getLatestResult();
				result = new JSONObject(data);
			} catch (Exception ex) {
				Log.d(LOCALTAG, "getLatestResult failed", ex);
			}

			return result;
		}

		private int getTimerMilliseconds()
		{
			int result = -1;
			
			try {
				result = mApi.getTimerMilliseconds();
			} catch (Exception ex) {
				Log.d(LOCALTAG, "getTimerMilliseconds failed", ex);
			}
			
			return result;
		}

	}

	protected class ExecuteResult {

		/*
		 ************************************************************************************************
		 * Fields 
		 ************************************************************************************************
		 */
		private ExecuteStatus mStatus;
		private JSONObject mData;
		private boolean mFinished = true;

		public ExecuteStatus getStatus() {
			return this.mStatus;
		}
		
		public void setStatus(ExecuteStatus pStatus) {
			this.mStatus = pStatus;
		}
		
		public JSONObject getData() {
			return this.mData;
		}
		
		public void setData(JSONObject pData) {
			this.mData = pData;
		}
		
		public boolean isFinished() {
			return this.mFinished;
		}

		public void setFinished(boolean pFinished) {
			this.mFinished = pFinished;
		}
		
		/*
		 ************************************************************************************************
		 * Constructors 
		 ************************************************************************************************
		 */
		public ExecuteResult(ExecuteStatus pStatus) {
			this.mStatus = pStatus;
		}
		
		public ExecuteResult(ExecuteStatus pStatus, JSONObject pData) {
			this.mStatus = pStatus;
			this.mData = pData;
		}

		public ExecuteResult(ExecuteStatus pStatus, JSONObject pData, boolean pFinished) {
			this.mStatus = pStatus;
			this.mData = pData;
			this.mFinished = pFinished;
		}

	}

	public interface IUpdateListener {
		public void handleUpdate(ExecuteResult logicResult, Object[] listenerExtras);
		public void closeListener(ExecuteResult logicResult, Object[] listenerExtras);
	}
	
	/*
	 ************************************************************************************************
	 * Enums 
	 ************************************************************************************************
	 */
	protected enum ExecuteStatus {
		OK,
		ERROR,
		INVALID_ACTION
	}


}


================================================
FILE: src/android/BootReceiver.java
================================================
package com.red_folder.phonegap.plugin.backgroundservice;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;

public class BootReceiver extends BroadcastReceiver {  
	
	/*
	 ************************************************************************************************
	 * Overriden Methods 
	 ************************************************************************************************
	 */
	@Override  
	public void onReceive(Context context, Intent intent) {
		
		// Get all the registered and loop through and start them
		String[] serviceList = PropertyHelper.getBootServices(context);
		
		if (serviceList != null) {
			for (int i = 0; i < serviceList.length; i++)
			{
				// Fix to https://github.com/Red-Folder/bgs-core/issues/18
				// Gets the class from string
				Class<?> serviceClass = ReflectionHelper.LoadClass(serviceList[i]);

				Intent serviceIntent = new Intent(context, serviceClass);         
				context.startService(serviceIntent);
			}
		}
	} 
	
} 


================================================
FILE: src/android/PropertyHelper.java
================================================
package com.red_folder.phonegap.plugin.backgroundservice;

import android.content.Context;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;

public class PropertyHelper {
	
	/*
	 ************************************************************************************************
	 * Fields 
	 ************************************************************************************************
	 */
	private final static String KEY_BOOTSERVICES = "com.red_folder.phonegap.plugin.backgroundservice.BootServices";

	/*
	 ************************************************************************************************
	 * Public Methods 
	 ************************************************************************************************
	 */
	protected static String[] getBootServices(Context context) {
		String serviceList = getBootServicesString(context);
				
		if (serviceList.length() == 0)
			return null;
		else
			return serviceList.split(";");
	}

	protected static void addBootService(Context context, String serviceName) {
		String serviceList = getBootServicesString(context);
		
		if (serviceList.length() == 0)
			serviceList = serviceName;
		else
			if (serviceList.contains(serviceName)) {
				// Already in the list, so ignore the request
			} else {
				serviceList += ";" + serviceName;
			}
		
		saveBootServices(context, serviceList);
	}

	protected static void removeBootService(Context context, String serviceName) {
		String serviceList = getBootServicesString(context);
		
		String newServiceList = "";
		if (serviceList.length() > 0)
		{
			if (serviceList.contains(serviceName)) {
				String[] services = serviceList.split(";");
				for (int i = 0; i < services.length; i++) {
					if (!services[i].contains(serviceName))
						newServiceList += ";" + services[i];
				}
			}
		}
		
		saveBootServices(context, newServiceList);
	}

	protected static boolean isBootService(Context context, String serviceName) {
		String serviceList = getBootServicesString(context);
		boolean result = false;
		
		if (serviceList.length() > 0)
		{
			if (serviceList.contains(serviceName)) {
				result = true;
			}
		}
		
		return result;
	}

	/*
	 ************************************************************************************************
	 * Private Methods 
	 ************************************************************************************************
	 */
	private static void saveBootServices(Context context, String serviceList) {
		SharedPreferences.Editor editor = getEditor(context);
        editor.putString(KEY_BOOTSERVICES, serviceList);
        editor.commit(); // Very important
	}
	
	private static String getBootServicesString(Context context) {
		SharedPreferences sharedPrefs = getSharedPreferences(context);  

		return sharedPrefs.getString(KEY_BOOTSERVICES, "");
	}
	
	private static SharedPreferences getSharedPreferences(Context context) {
		return PreferenceManager.getDefaultSharedPreferences(context);
	}
	
	private static SharedPreferences.Editor getEditor(Context context) {
		SharedPreferences sharedPrefs = getSharedPreferences(context);
		return sharedPrefs.edit();
	}
}


================================================
FILE: src/android/ReflectionHelper.java
================================================
package com.red_folder.phonegap.plugin.backgroundservice;

import android.util.Log;

public class ReflectionHelper {
	
	/*
	 ************************************************************************************************
	 * Static values 
	 ************************************************************************************************
	 */
	public static final String TAG = ReflectionHelper.class.getSimpleName();
	
	public static Class<?> LoadClass(String className) {
		Class<?> result = null;
	
		Log.d(TAG, "Attempting to load call: " + className);
		ClassLoader classLoader = ReflectionHelper.class.getClassLoader();

		try {
			result = classLoader.loadClass(className);
			Log.d(TAG, "Class loaded");
		} catch (ClassNotFoundException ex) {
			Log.d(TAG, "Class failed to load");
			Log.d(TAG, ex.getMessage());
		}
		
		return result;
	}
}


================================================
FILE: www/backgroundService.js
================================================
/*
 * Copyright 2013 Red Folder Consultancy Ltd
 *   
 * Licensed under the Apache License, Version 2.0 (the "License");   
 * you may not use this file except in compliance with the License.   
 * You may obtain a copy of the License at       
 * 
 * 	http://www.apache.org/licenses/LICENSE-2.0   
 *
 * Unless required by applicable law or agreed to in writing, software   
 * distributed under the License is distributed on an "AS IS" BASIS,   
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   
 * See the License for the specific language governing permissions and   
 * limitations under the License.
 */

 /*
  * Declare a factory class which is used to create the background service "wrapper"
  */
function BackgroundServiceFactory() { }

BackgroundServiceFactory.prototype.create = function (serviceName) {
	var exec = require("cordova/exec");
	
	var BackgroundService = function (serviceName) {
		var ServiceName = serviceName;
		this.getServiceName = function() {
			return ServiceName;
		};
	};

	/**
	  * All methods attempt to return the following data in both the success and failure callbacks
	  * Front end development should take into account any all or all of these values may be null
	  *
	  * Following returned in the JSONObject:
	  *		Boolean Success - was the call a success
	  *		int ErrorCode - Error code if an error occurred, else will be zero
	  *		String ErrorMessage - Text representation of the error code
	  *		Boolean ServiceRunning - True if the Service is running
	  *		Boolean TimerEnabled - True if the Timer is enabled
	  *		Boolean RegisteredForBootStart - True if the Service is registered for boot start
	  *		JSONObject Configuration - A JSONObject of the configuration of the service (contents dependant on the service)
	  *		JSONObject LastestResult - A JSONObject of the last result of the service (contents dependant on the service)
	  *		int TimerMilliseconds - Milliseconds used by the background service if Timer enabled
	  *		Boolean RegisteredForUpdates - True if the Service is registered to send updates to the front-end
	  */

	/**
	  * Starts the Service
	  * 
	  * @param successCallback The callback which will be called if the method is successful
	  * @param failureCallback The callback which will be called if the method encounters an error
	  */
	BackgroundService.prototype.startService = function(successCallback, failureCallback) { 
		return exec(	successCallback,      
						failureCallback,      
						'BackgroundServicePlugin',      
						'startService',      
						[this.getServiceName()]);
	};

	/**
	  * Stops the Service
	  *
	  * @param successCallback The callback which will be called if the method is successful
	  * @param failureCallback The callback which will be called if the method encounters an error
	  */
	BackgroundService.prototype.stopService = function(successCallback, failureCallback) { 
		return exec(	successCallback,      
						failureCallback,      
						'BackgroundServicePlugin',      
						'stopService',      
						[this.getServiceName()]);
	};

	/**
	  * Enables the Service Timer
	  *
	  * @param milliseconds The milliseconds used for the timer
	  * @param successCallback The callback which will be called if the method is successful
	  * @param failureCallback The callback which will be called if the method encounters an error
	  */
	BackgroundService.prototype.enableTimer = function(milliseconds, successCallback, failureCallback) { 
		return exec(	successCallback,      
						failureCallback,      
						'BackgroundServicePlugin',      
						'enableTimer',      
						[this.getServiceName(), milliseconds]);
	};

	/**
	  * Disabled the Service Timer
	  *
	  * @param successCallback The callback which will be called if the method is successful
	  * @param failureCallback The callback which will be called if the method encounters an error
	  */
	BackgroundService.prototype.disableTimer = function(successCallback, failureCallback) { 
		return exec(	successCallback,      
						failureCallback,      
						'BackgroundServicePlugin',      
						'disableTimer',      
						[this.getServiceName()]);
	};

	/**
	  * Sets the configuration for the service
	  *
	  * @param configuration JSONObject to be sent to the service
	  * @param successCallback The callback which will be called if the method is successful
	  * @param failureCallback The callback which will be called if the method encounters an error
	  */
	BackgroundService.prototype.setConfiguration = function(configuration, successCallback, failureCallback) { 
		return exec(	successCallback,      
						failureCallback,      
						'BackgroundServicePlugin',      
						'setConfiguration',      
						[this.getServiceName(), configuration]);
	};

	/**
	  * Registers the service for Boot Start
	  *
	  * @param successCallback The callback which will be called if the method is successful
	  * @param failureCallback The callback which will be called if the method encounters an error
	  */
	BackgroundService.prototype.registerForBootStart = function(successCallback, failureCallback) { 
		return exec(	successCallback,      
						failureCallback,      
						'BackgroundServicePlugin',      
						'registerForBootStart',      
						[this.getServiceName()]);
	};

	/**
	  * Deregisters the service for Boot Start
	  *
	  * @param successCallback The callback which will be called if the method is successful
	  * @param failureCallback The callback which will be called if the method encounters an error
	  */
	BackgroundService.prototype.deregisterForBootStart = function(successCallback, failureCallback) { 
		return exec(	successCallback,      
						failureCallback,      
						'BackgroundServicePlugin',      
						'deregisterForBootStart',      
						[this.getServiceName()]);
	};

	/**
	  * Get the current status of the service.	
	  * 
	  * @param successCallback The callback which will be called if the method is successful
	  * @param failureCallback The callback which will be called if the method encounters an error
	  */
	BackgroundService.prototype.isRegisteredForBootStart = function(successCallback, failureCallback) { 
		return exec(	successCallback,      
						failureCallback,      
						'BackgroundServicePlugin',      
						'isRegisteredForBootStart',      
						[this.getServiceName()]);
	};


	/**
	  * Returns the status of the service
	  *
	  * @param successCallback The callback which will be called if the method is successful
	  * @param failureCallback The callback which will be called if the method encounters an error
	  */
	BackgroundService.prototype.getStatus = function(successCallback, failureCallback) { 
		return exec(	successCallback,      
						failureCallback,      
						'BackgroundServicePlugin',      
						'getStatus',      
						[this.getServiceName()]);
	};

	/**
	  * Returns the doWork once
	  *
	  * @param successCallback The callback which will be called if the method is successful
	  * @param failureCallback The callback which will be called if the method encounters an error
	  */
	BackgroundService.prototype.runOnce = function(successCallback, failureCallback) { 
		return exec(	successCallback,      
						failureCallback,      
						'BackgroundServicePlugin',      
						'runOnce',      
						[this.getServiceName()]);
	};

	/**
	  * Registers for doWork() updates
	  *
	  * @param successCallback The callback which will be called if the method is successful
	  * @param failureCallback The callback which will be called if the method encounters an error
	  */
	BackgroundService.prototype.registerForUpdates = function(successCallback, failureCallback) { 
		return exec(	successCallback,      
						failureCallback,      
						'BackgroundServicePlugin',      
						'registerForUpdates',      
						[this.getServiceName()]);
	};

	/**
	  * Deregisters for doWork() updates
	  *
	  * @param successCallback The callback which will be called if the method is successful
	  * @param failureCallback The callback which will be called if the method encounters an error
	  */
	BackgroundService.prototype.deregisterForUpdates = function(successCallback, failureCallback) { 
		return exec(	successCallback,      
						failureCallback,      
						'BackgroundServicePlugin',      
						'deregisterForUpdates',      
						[this.getServiceName()]);
	};

	var backgroundService = new BackgroundService(serviceName);
	return backgroundService;
}; 

module.exports = new BackgroundServiceFactory();
Download .txt
gitextract_sh7pmjsj/

├── LICENSE
├── README.md
├── aidl/
│   └── android/
│       ├── BackgroundServiceApi.aidl
│       └── BackgroundServiceListener.aidl
├── package.json
├── plugin.xml
├── src/
│   └── android/
│       ├── BackgroundService.java
│       ├── BackgroundServicePlugin.java
│       ├── BackgroundServicePluginLogic.java
│       ├── BootReceiver.java
│       ├── PropertyHelper.java
│       └── ReflectionHelper.java
└── www/
    └── backgroundService.js
Download .txt
SYMBOL INDEX (109 symbols across 7 files)

FILE: src/android/BackgroundService.java
  class BackgroundService (line 23) | public abstract class BackgroundService extends Service {
    method setPauseDuration (line 49) | public void setPauseDuration(long pauseDuration) {
    method getEnabled (line 56) | public Boolean getEnabled() {
    method setEnabled (line 62) | public void setEnabled(Boolean enabled) {
    method getMilliseconds (line 70) | public int getMilliseconds() {
    method setMilliseconds (line 77) | public void setMilliseconds(int milliseconds) {
    method getLatestResult (line 85) | protected JSONObject getLatestResult() {
    method setLatestResult (line 91) | protected void setLatestResult(JSONObject value) {
    method restartTimer (line 97) | public void restartTimer() {
    method onBind (line 115) | @Override
    method onStartCommand (line 121) | @Override
    method onDestroy (line 130) | @Override
    method runOnce (line 143) | protected void runOnce() {
    method getLatestResult (line 161) | @Override
    method addListener (line 171) | @Override
    method removeListener (line 183) | @Override
    method enableTimer (line 206) | @Override
    method disableTimer (line 219) | @Override
    method isTimerEnabled (line 228) | @Override
    method getConfiguration (line 233) | @Override
    method setConfiguration (line 242) | @Override
    method getTimerMilliseconds (line 257) | @Override
    method run (line 262) | @Override
    method initialiseService (line 268) | private void initialiseService() {
    method cleanupService (line 287) | private void cleanupService() {
    method setupTimerTask (line 307) | private void setupTimerTask () {
    method stopTimerTask (line 323) | private void stopTimerTask() {
    method getTimerTask (line 341) | private TimerTask getTimerTask() {
    method doWorkWrapper (line 381) | private void doWorkWrapper() {
    method initialiseLatestResult (line 412) | protected abstract JSONObject initialiseLatestResult();
    method doWork (line 413) | protected abstract JSONObject doWork();
    method getConfig (line 414) | protected abstract JSONObject getConfig();
    method setConfig (line 415) | protected abstract void setConfig(JSONObject config);
    method onTimerEnabled (line 417) | protected void onTimerEnabled() {
    method onTimerDisabled (line 420) | protected void onTimerDisabled() {
    method onPause (line 423) | protected void onPause() {
    method onPauseComplete (line 426) | protected void onPauseComplete() {

FILE: src/android/BackgroundServicePlugin.java
  class BackgroundServicePlugin (line 14) | public class BackgroundServicePlugin extends CordovaPlugin implements Ba...
    method execute (line 39) | @Override
    method onDestroy (line 97) | @Override
    method handleUpdate (line 112) | public void handleUpdate(ExecuteResult logicResult, Object[] listenerE...
    method closeListener (line 118) | public void closeListener(ExecuteResult logicResult, Object[] listener...
    method sendUpdateToListener (line 129) | private void sendUpdateToListener(ExecuteResult logicResult, Object[] ...
    method transformResult (line 143) | private PluginResult transformResult(ExecuteResult logicResult) {

FILE: src/android/BackgroundServicePluginLogic.java
  class BackgroundServicePluginLogic (line 20) | public class BackgroundServicePluginLogic {
    method BackgroundServicePluginLogic (line 102) | public BackgroundServicePluginLogic(Context pContext) {
    method isActionValid (line 124) | public boolean isActionValid(String action) {
    method execute (line 148) | public ExecuteResult execute(String action, JSONArray data) {
    method execute (line 152) | public ExecuteResult execute(String action, JSONArray data, IUpdateLis...
    method onDestroy (line 230) | public void onDestroy() {
    class ServiceDetails (line 267) | protected class ServiceDetails {
      method ServiceDetails (line 302) | public ServiceDetails(Context context, String serviceName)
      method initialise (line 313) | public void initialise()
      method isInitialised (line 323) | public boolean isInitialised()
      method startService (line 328) | public ExecuteResult startService()
      method stopService (line 351) | public ExecuteResult stopService()
      method enableTimer (line 378) | public ExecuteResult enableTimer(JSONArray data)
      method disableTimer (line 394) | public ExecuteResult disableTimer()
      method registerForBootStart (line 409) | public ExecuteResult registerForBootStart()
      method deregisterForBootStart (line 425) | public ExecuteResult deregisterForBootStart()
      method setConfiguration (line 441) | public ExecuteResult setConfiguration(JSONArray data)
      method getStatus (line 467) | public ExecuteResult getStatus()
      method runOnce (line 476) | public ExecuteResult runOnce()
      method registerForUpdates (line 495) | public ExecuteResult registerForUpdates(IUpdateListener listener, Ob...
      method deregisterForUpdates (line 524) | public ExecuteResult deregisterForUpdates()
      method close (line 547) | public void close()
      method deregisterListener (line 567) | private boolean deregisterListener() {
      method bindToService (line 595) | private boolean bindToService() {
      method onServiceConnected (line 633) | @Override
      method onServiceDisconnected (line 651) | @Override
      method handleUpdate (line 662) | @Override
      method getUniqueID (line 667) | @Override
      method handleLatestResult (line 673) | private void handleLatestResult() {
      method createJSONResult (line 694) | private JSONObject createJSONResult(Boolean success, int errorCode, ...
      method isServiceRunning (line 726) | private boolean isServiceRunning()
      method isTimerEnabled (line 745) | private Boolean isTimerEnabled()
      method isRegisteredForBootStart (line 758) | private Boolean isRegisteredForBootStart()
      method isRegisteredForUpdates (line 771) | private Boolean isRegisteredForUpdates()
      method getConfiguration (line 779) | private JSONObject getConfiguration()
      method getLatestResult (line 793) | private JSONObject getLatestResult()
      method getTimerMilliseconds (line 807) | private int getTimerMilliseconds()
    class ExecuteResult (line 822) | protected class ExecuteResult {
      method getStatus (line 833) | public ExecuteStatus getStatus() {
      method setStatus (line 837) | public void setStatus(ExecuteStatus pStatus) {
      method getData (line 841) | public JSONObject getData() {
      method setData (line 845) | public void setData(JSONObject pData) {
      method isFinished (line 849) | public boolean isFinished() {
      method setFinished (line 853) | public void setFinished(boolean pFinished) {
      method ExecuteResult (line 862) | public ExecuteResult(ExecuteStatus pStatus) {
      method ExecuteResult (line 866) | public ExecuteResult(ExecuteStatus pStatus, JSONObject pData) {
      method ExecuteResult (line 871) | public ExecuteResult(ExecuteStatus pStatus, JSONObject pData, boolea...
    type IUpdateListener (line 879) | public interface IUpdateListener {
      method handleUpdate (line 880) | public void handleUpdate(ExecuteResult logicResult, Object[] listene...
      method closeListener (line 881) | public void closeListener(ExecuteResult logicResult, Object[] listen...
    type ExecuteStatus (line 889) | protected enum ExecuteStatus {

FILE: src/android/BootReceiver.java
  class BootReceiver (line 7) | public class BootReceiver extends BroadcastReceiver {
    method onReceive (line 14) | @Override

FILE: src/android/PropertyHelper.java
  class PropertyHelper (line 7) | public class PropertyHelper {
    method getBootServices (line 21) | protected static String[] getBootServices(Context context) {
    method addBootService (line 30) | protected static void addBootService(Context context, String serviceNa...
    method removeBootService (line 45) | protected static void removeBootService(Context context, String servic...
    method isBootService (line 63) | protected static boolean isBootService(Context context, String service...
    method saveBootServices (line 82) | private static void saveBootServices(Context context, String serviceLi...
    method getBootServicesString (line 88) | private static String getBootServicesString(Context context) {
    method getSharedPreferences (line 94) | private static SharedPreferences getSharedPreferences(Context context) {
    method getEditor (line 98) | private static SharedPreferences.Editor getEditor(Context context) {

FILE: src/android/ReflectionHelper.java
  class ReflectionHelper (line 5) | public class ReflectionHelper {
    method LoadClass (line 14) | public static Class<?> LoadClass(String className) {

FILE: www/backgroundService.js
  function BackgroundServiceFactory (line 20) | function BackgroundServiceFactory() { }
Condensed preview — 13 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (77K chars).
[
  {
    "path": "LICENSE",
    "chars": 607,
    "preview": " Copyright 2013 Red Folder Consultancy Ltd\n    \n Licensed under the Apache License, Version 2.0 (the \"License\");   \n you"
  },
  {
    "path": "README.md",
    "chars": 3097,
    "preview": "# Important Notice\nPlease be aware that I'm no longer actively maintaining this plugin.\n\nI believe the problem it solved"
  },
  {
    "path": "aidl/android/BackgroundServiceApi.aidl",
    "chars": 555,
    "preview": "package com.red_folder.phonegap.plugin.backgroundservice;   \n\nimport com.red_folder.phonegap.plugin.backgroundservice.Ba"
  },
  {
    "path": "aidl/android/BackgroundServiceListener.aidl",
    "chars": 154,
    "preview": "package com.red_folder.phonegap.plugin.backgroundservice;   \n\ninterface BackgroundServiceListener {     \n\tvoid handleUpd"
  },
  {
    "path": "package.json",
    "chars": 665,
    "preview": "{\n  \"name\": \"com.red_folder.phonegap.plugin.backgroundservice\",\n  \"version\": \"2.0.0\",\n  \"description\": \"Framework code t"
  },
  {
    "path": "plugin.xml",
    "chars": 2706,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<plugin xmlns=\"http://apache.org/cordova/ns/plugins/1.0\"\n        xmlns:android=\"h"
  },
  {
    "path": "src/android/BackgroundService.java",
    "chars": 11239,
    "preview": "package com.red_folder.phonegap.plugin.backgroundservice;\n\nimport java.text.SimpleDateFormat;\nimport java.util.ArrayList"
  },
  {
    "path": "src/android/BackgroundServicePlugin.java",
    "chars": 6441,
    "preview": "package com.red_folder.phonegap.plugin.backgroundservice;\n\nimport org.apache.cordova.CallbackContext;\nimport org.apache."
  },
  {
    "path": "src/android/BackgroundServicePluginLogic.java",
    "chars": 29723,
    "preview": "package com.red_folder.phonegap.plugin.backgroundservice;\n\nimport java.util.Enumeration;\nimport java.util.Hashtable;\n\nim"
  },
  {
    "path": "src/android/BootReceiver.java",
    "chars": 1037,
    "preview": "package com.red_folder.phonegap.plugin.backgroundservice;\n\nimport android.content.BroadcastReceiver;\nimport android.cont"
  },
  {
    "path": "src/android/PropertyHelper.java",
    "chars": 3154,
    "preview": "package com.red_folder.phonegap.plugin.backgroundservice;\n\nimport android.content.Context;\nimport android.content.Shared"
  },
  {
    "path": "src/android/ReflectionHelper.java",
    "chars": 883,
    "preview": "package com.red_folder.phonegap.plugin.backgroundservice;\r\n\r\nimport android.util.Log;\r\n\r\npublic class ReflectionHelper {"
  },
  {
    "path": "www/backgroundService.js",
    "chars": 8496,
    "preview": "/*\n * Copyright 2013 Red Folder Consultancy Ltd\n *   \n * Licensed under the Apache License, Version 2.0 (the \"License\");"
  }
]

About this extraction

This page contains the full source code of the Red-Folder/bgs-core GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 13 files (67.1 KB), approximately 15.2k tokens, and a symbol index with 109 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!