/*
* PhoneGap is available under *either* the terms of the modified BSD license *or* the
* MIT License (2008). See http://opensource.org/licenses/alphabetical for full text.
*
* Copyright (c) 2005-2010, Nitobi Software Inc.
* Copyright (c) 2010-2011, IBM Corporation
*/
package com.phonegap.battery;
import java.util.Enumeration;
import java.util.Hashtable;
import net.rim.device.api.system.Application;
import net.rim.device.api.system.DeviceInfo;
import net.rim.device.api.system.SystemListener;
import com.phonegap.api.Plugin;
import com.phonegap.api.PluginResult;
import com.phonegap.json4j.JSONArray;
import com.phonegap.json4j.JSONException;
import com.phonegap.json4j.JSONObject;
import com.phonegap.util.Logger;
/**
* The Battery plug-in. This class provides information about the state of the
* battery on the phone. The following actions are supported:
*
* start - Start listening for changes in battery level (%) and batter
* charging state.
* stop - Stop listening for changes in battery level and state.
*/
public class Battery extends Plugin {
/** Actions to start and stop listening for battery changes. */
private final static String ACTION_START = "start";
private final static String ACTION_STOP = "stop";
/** The percentage of battery remaining. */
private final static String LEVEL = "level";
/** Whether the battery is currently charging or not. */
private final static String CHARGING = "isPlugged";
// The set of call back IDs to send results to. Using Hashtable because
// BlackBerry does not support Collections. There should only ever be one
// call back ID, but this allows multiple.
private Hashtable callbackIds = new Hashtable();
private SystemListener batteryListener = null;
/**
* Executes the requested action and returns a PluginResult.
*
* @param action
* The action to execute.
* @param callbackId
* The callback ID to be invoked upon action completion
* @param args
* JSONArry of arguments for the action.
* @return A PluginResult object with a status and message.
*/
public PluginResult execute(String action, JSONArray args, String callbackId) {
PluginResult result = null;
if (ACTION_START.equals(action)) {
// Register a listener to detect battery changes.
addListener(callbackId);
// Don't return any result now, since battery status results are
// sent when listener is notified.
result = new PluginResult(PluginResult.Status.NO_RESULT);
// Must keep the call back active for future events.
result.setKeepCallback(true);
} else if (ACTION_STOP.equals(action)) {
// Remove the battery listener and cleanup call back IDs.
removeListener();
result = new PluginResult(PluginResult.Status.OK);
} else {
result = new PluginResult(PluginResult.Status.INVALID_ACTION,
"Battery: Invalid action: " + action);
}
return result;
}
/**
* Remove the listener when the application is destroyed. Note that onPause
* is not overridden, so the listener will continue if the application is
* simply paused instead of destroyed.
*/
public void onDestroy() {
removeListener();
}
/**
* Adds a SystemListener to listen for changes to the battery state. The
* listener is only registered if one has not already been added. If a
* listener has already been registered the call back id is simply saved so
* that it can be notified upon next battery state change.
*
* @param callbackId
* The reference point to call back when a listener event occurs.
*/
private synchronized void addListener(String callbackId) {
callbackIds.put(callbackId, callbackId);
// Only register a listener if one has not been registered.
if (batteryListener == null) {
batteryListener = new SystemListener() {
// Initialize the charging state and battery level.
private boolean prevChargeState = (DeviceInfo
.getBatteryStatus() & DeviceInfo.BSTAT_CHARGING) != 0;
private int prevLevel = DeviceInfo.getBatteryLevel();
public void batteryGood() { }
public void batteryLow() { }
public void batteryStatusChange(int status) {
// The status bits passed into this method are unreliable
// in determining when the battery level has changed.
// Instead, when any state change occurs, get the current
// battery level and report the change if it is different
// then previous value.
int newLevel = DeviceInfo.getBatteryLevel();
boolean newChargeState = (DeviceInfo.BSTAT_CHARGING & status) != 0;
// Report change if level or charge state is different then
// previous values.
if (newLevel != prevLevel || newChargeState != prevChargeState) {
prevChargeState = newChargeState;
prevLevel = newLevel;
// Store the retrieved properties in a JSON object.
JSONObject connectionInfo = new JSONObject();
try {
connectionInfo.put(LEVEL, newLevel);
connectionInfo.put(CHARGING, newChargeState);
} catch (JSONException e) {
Logger.error("JSONException: " + e.getMessage());
return;
}
PluginResult result = new PluginResult(
PluginResult.Status.OK, connectionInfo);
sendSuccessResult(result, true);
}
}
public void powerOff() { }
public void powerUp() { }
};
Application.getApplication().addSystemListener(batteryListener);
}
}
/**
* Remove the registered battery status listener and cleanup the call back
* IDs.
*/
private synchronized void removeListener() {
if (batteryListener != null) {
// Remove the battery listener.
Application.getApplication().removeSystemListener(batteryListener);
batteryListener = null;
// Close out the call back IDs.
sendSuccessResult(new PluginResult(PluginResult.Status.OK), false);
callbackIds.clear();
}
}
/**
* Helper function to send the PluginResult to the saved call back IDs.
*
* @param result
* the PluginResult to return
* @param keepCallback
* Boolean value indicating whether to keep the call back id
* active.
*/
private void sendSuccessResult(PluginResult result, boolean keepCallback) {
if (result != null) {
// Must keep the call back active for future events.
result.setKeepCallback(keepCallback);
// Iterate through the saved call back IDs. Really should only ever
// be one.
for (Enumeration callbacks = this.callbackIds.elements(); callbacks
.hasMoreElements();) {
success(result, (String) callbacks.nextElement());
}
}
}
}