For Auto, display battery status as that of a connected device.

For Android Auto Embedded, we would like to display the battery status
of a device that is connected via Bluetooth and not the battery status
of the device itself (which would not make sense in Auto).

To accomplish this, introduce a new CarBatteryController that only
monitors the status of battery via Bluetooth. Note that AAE is not
explicitly handling the battery icon that appears in the quick settings
because this will be hidden for Auto.

This CarBatteryController implements a new BatteryController interface.
What used to be the BatteryController has been moved to the
BatteryControllerImpl class.

Bug: 28002775
Change-Id: I2285bcbd3d207cdcc1ac5a98ec3685d4fff0f0d9
This commit is contained in:
Anthony Chen
2016-04-06 16:15:14 -07:00
parent 0e89f98044
commit da62fdcd50
5 changed files with 541 additions and 153 deletions

View File

@@ -0,0 +1,271 @@
/*
* Copyright (C) 2016 The Android Open Source Project
*
* 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.
*/
package com.android.systemui.statusbar.car;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHeadsetClient;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.BluetoothProfile.ServiceListener;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.util.Log;
import com.android.systemui.statusbar.policy.BatteryController;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
/**
* A {@link BatteryController} that is specific to the Auto use-case. For Auto, the battery icon
* displays the battery status of a device that is connected via bluetooth and not the system's
* battery.
*/
public class CarBatteryController extends BroadcastReceiver implements BatteryController {
private static final String TAG = "CarBatteryController";
// According to the Bluetooth HFP 1.5 specification, battery levels are indicated by a
// value from 1-5, where these values represent the following:
// 0%% - 0, 1-25%% - 1, 26-50%% - 2, 51-75%% - 3, 76-99%% - 4, 100%% - 5
// As a result, set the level as the average within that range.
private static final int BATTERY_LEVEL_EMPTY = 0;
private static final int BATTERY_LEVEL_1 = 12;
private static final int BATTERY_LEVEL_2 = 28;
private static final int BATTERY_LEVEL_3 = 63;
private static final int BATTERY_LEVEL_4 = 87;
private static final int BATTERY_LEVEL_FULL = 100;
private static final int INVALID_BATTERY_LEVEL = -1;
private final Context mContext;
private final BluetoothAdapter mAdapter = BluetoothAdapter.getDefaultAdapter();
private BluetoothHeadsetClient mBluetoothHeadsetClient;
private final ArrayList<BatteryStateChangeCallback> mChangeCallbacks = new ArrayList<>();
private int mLevel;
/**
* An interface indicating the container of a View that will display what the information
* in the {@link CarBatteryController}.
*/
public interface BatteryViewHandler {
void hideBatteryView();
void showBatteryView();
}
private BatteryViewHandler mBatteryViewHandler;
public CarBatteryController(Context context) {
mContext = context;
mAdapter.getProfileProxy(context.getApplicationContext(), mHfpServiceListener,
BluetoothProfile.HEADSET_CLIENT);
}
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.println("CarBatteryController state:");
pw.print(" mLevel=");
pw.println(mLevel);
}
@Override
public void setPowerSaveMode(boolean powerSave) {
// No-op. No power save mode for the car.
}
@Override
public void addStateChangedCallback(BatteryController.BatteryStateChangeCallback cb) {
mChangeCallbacks.add(cb);
// There is no way to know if the phone is plugged in or charging via bluetooth, so pass
// false for these values.
cb.onBatteryLevelChanged(mLevel, false /* pluggedIn */, false /* charging */);
cb.onPowerSaveChanged(false /* isPowerSave */);
}
@Override
public void removeStateChangedCallback(BatteryController.BatteryStateChangeCallback cb) {
mChangeCallbacks.remove(cb);
}
public void addBatteryViewHandler(BatteryViewHandler batteryViewHandler) {
mBatteryViewHandler = batteryViewHandler;
}
public void startListening() {
IntentFilter filter = new IntentFilter();
filter.addAction(BluetoothHeadsetClient.ACTION_CONNECTION_STATE_CHANGED);
filter.addAction(BluetoothHeadsetClient.ACTION_AG_EVENT);
mContext.registerReceiver(this, filter);
}
public void stopListening() {
mContext.unregisterReceiver(this);
}
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "onReceive(). action: " + action);
}
if (BluetoothHeadsetClient.ACTION_AG_EVENT.equals(action)) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "Received ACTION_AG_EVENT");
}
int batteryLevel = intent.getIntExtra(BluetoothHeadsetClient.EXTRA_BATTERY_LEVEL,
INVALID_BATTERY_LEVEL);
updateBatteryLevel(batteryLevel);
if (batteryLevel != INVALID_BATTERY_LEVEL && mBatteryViewHandler != null) {
mBatteryViewHandler.showBatteryView();
}
} else if (BluetoothHeadsetClient.ACTION_CONNECTION_STATE_CHANGED.equals(action)) {
int newState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1);
if (Log.isLoggable(TAG, Log.DEBUG)) {
int oldState = intent.getIntExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, -1);
Log.d(TAG, "ACTION_CONNECTION_STATE_CHANGED event: "
+ oldState + " -> " + newState);
}
BluetoothDevice device =
(BluetoothDevice)intent.getExtra(BluetoothDevice.EXTRA_DEVICE);
updateBatteryIcon(device, newState);
}
}
/**
* Converts the battery level to a percentage that can be displayed on-screen and notifies
* any {@link BatteryStateChangeCallback}s of this.
*/
private void updateBatteryLevel(int batteryLevel) {
if (batteryLevel == INVALID_BATTERY_LEVEL) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "Battery level invalid. Ignoring.");
}
return;
}
// The battery level is a value between 0-5. Let the default battery level be 0.
switch (batteryLevel) {
case 5:
mLevel = BATTERY_LEVEL_FULL;
break;
case 4:
mLevel = BATTERY_LEVEL_4;
break;
case 3:
mLevel = BATTERY_LEVEL_3;
break;
case 2:
mLevel = BATTERY_LEVEL_2;
break;
case 1:
mLevel = BATTERY_LEVEL_1;
break;
case 0:
default:
mLevel = BATTERY_LEVEL_EMPTY;
}
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "Battery level: " + batteryLevel + "; setting mLevel as: " + mLevel);
}
notifyBatteryLevelChanged();
}
/**
* Updates the display of the battery icon depending on the given connection state from the
* given {@link BluetoothDevice}.
*/
private void updateBatteryIcon(BluetoothDevice device, int newState) {
if (newState == BluetoothProfile.STATE_CONNECTED) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "Device connected");
}
if (mBatteryViewHandler != null) {
mBatteryViewHandler.showBatteryView();
}
if (mBluetoothHeadsetClient == null || device == null) {
return;
}
// Check if battery information is available and immediately update.
Bundle featuresBundle = mBluetoothHeadsetClient.getCurrentAgEvents(device);
if (featuresBundle == null) {
return;
}
int batteryLevel = featuresBundle.getInt(BluetoothHeadsetClient.EXTRA_BATTERY_LEVEL,
INVALID_BATTERY_LEVEL);
updateBatteryLevel(batteryLevel);
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "Device disconnected");
}
if (mBatteryViewHandler != null) {
mBatteryViewHandler.hideBatteryView();
}
}
}
@Override
public boolean isPowerSave() {
// Power save is not valid for the car, so always return false.
return false;
}
private void notifyBatteryLevelChanged() {
for (int i = 0, size = mChangeCallbacks.size(); i < size; i++) {
mChangeCallbacks.get(i)
.onBatteryLevelChanged(mLevel, false /* pluggedIn */, false /* charging */);
}
}
private final ServiceListener mHfpServiceListener = new ServiceListener() {
@Override
public void onServiceConnected(int profile, BluetoothProfile proxy) {
if (profile == BluetoothProfile.HEADSET_CLIENT) {
mBluetoothHeadsetClient = (BluetoothHeadsetClient) proxy;
}
}
@Override
public void onServiceDisconnected(int profile) {
if (profile == BluetoothProfile.HEADSET_CLIENT) {
mBluetoothHeadsetClient = null;
}
}
};
}

View File

@@ -22,37 +22,75 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.PixelFormat;
import android.os.Handler;
import android.os.Looper;
import android.os.RemoteException;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup.LayoutParams;
import android.view.ViewStub;
import android.view.WindowManager;
import com.android.systemui.BatteryMeterView;
import com.android.systemui.R;
import com.android.systemui.recents.Recents;
import com.android.systemui.recents.misc.SystemServicesProxy;
import com.android.systemui.recents.misc.SystemServicesProxy.TaskStackListener;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.phone.PhoneStatusBar;
import com.android.systemui.statusbar.phone.PhoneStatusBarView;
import com.android.systemui.statusbar.policy.BatteryController;
/**
* A status bar (and navigation bar) tailored for the automotive use case.
*/
public class CarStatusBar extends PhoneStatusBar {
public class CarStatusBar extends PhoneStatusBar implements
CarBatteryController.BatteryViewHandler {
private static final String TAG = "CarStatusBar";
private TaskStackListenerImpl mTaskStackListener;
private CarNavigationBarView mCarNavigationBar;
private CarNavigationBarController mController;
private FullscreenUserSwitcher mFullscreenUserSwitcher;
private CarBatteryController mCarBatteryController;
private BatteryMeterView mBatteryMeterView;
@Override
public void start() {
super.start();
mTaskStackListener = new TaskStackListenerImpl();
SystemServicesProxy.getInstance(mContext).registerTaskStackListener(mTaskStackListener);
registerPackageChangeReceivers();
mCarBatteryController.startListening();
}
@Override
public void destroy() {
mCarBatteryController.stopListening();
super.destroy();
}
@Override
protected PhoneStatusBarView makeStatusBarView() {
PhoneStatusBarView statusBarView = super.makeStatusBarView();
mBatteryMeterView = ((BatteryMeterView) statusBarView.findViewById(R.id.battery));
// By default, the BatteryMeterView should not be visible. It will be toggled visible
// when a device has connected by bluetooth.
mBatteryMeterView.setVisibility(View.GONE);
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "makeStatusBarView(). mBatteryMeterView: " + mBatteryMeterView);
}
return statusBarView;
}
@Override
protected BatteryController createBatteryController() {
mCarBatteryController = new CarBatteryController(mContext);
mCarBatteryController.addBatteryViewHandler(this);
return mCarBatteryController;
}
@Override
@@ -85,6 +123,28 @@ public class CarStatusBar extends PhoneStatusBar {
}
@Override
public void showBatteryView() {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "showBatteryView(). mBatteryMeterView: " + mBatteryMeterView);
}
if (mBatteryMeterView != null) {
mBatteryMeterView.setVisibility(View.VISIBLE);
}
}
@Override
public void hideBatteryView() {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "hideBatteryView(). mBatteryMeterView: " + mBatteryMeterView);
}
if (mBatteryMeterView != null) {
mBatteryMeterView.setVisibility(View.GONE);
}
}
private BroadcastReceiver mPackageChangeReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {

View File

@@ -21,9 +21,7 @@ import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.annotation.NonNull;
import android.app.ActivityManager;
import android.app.ActivityManager.StackId;
import android.app.ActivityManagerNative;
import android.app.ActivityOptions;
import android.app.IActivityManager;
import android.app.Notification;
import android.app.PendingIntent;
@@ -147,6 +145,7 @@ import com.android.systemui.statusbar.phone.UnlockMethodCache.OnUnlockMethodChan
import com.android.systemui.statusbar.policy.AccessibilityController;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback;
import com.android.systemui.statusbar.policy.BatteryControllerImpl;
import com.android.systemui.statusbar.policy.BluetoothControllerImpl;
import com.android.systemui.statusbar.policy.BrightnessMirrorController;
import com.android.systemui.statusbar.policy.CastControllerImpl;
@@ -826,7 +825,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
// Other icons
mLocationController = new LocationControllerImpl(mContext,
mHandlerThread.getLooper()); // will post a notification
mBatteryController = new BatteryController(mContext);
mBatteryController = createBatteryController();
mBatteryController.addStateChangedCallback(new BatteryStateChangeCallback() {
@Override
public void onPowerSaveChanged(boolean isPowerSave) {
@@ -943,6 +942,10 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
return mStatusBarView;
}
protected BatteryController createBatteryController() {
return new BatteryControllerImpl(mContext);
}
@Override
protected void reInflateViews() {
super.reInflateViews();

View File

@@ -16,158 +16,33 @@
package com.android.systemui.statusbar.policy;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.BatteryManager;
import android.os.Handler;
import android.os.PowerManager;
import android.util.Log;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
public class BatteryController extends BroadcastReceiver {
private static final String TAG = "BatteryController";
public interface BatteryController {
/**
* Prints the current state of the {@link BatteryController} to the given {@link PrintWriter}.
*/
void dump(FileDescriptor fd, PrintWriter pw, String[] args);
public static final String ACTION_LEVEL_TEST = "com.android.systemui.BATTERY_LEVEL_TEST";
/**
* Sets if the current device is in power save mode.
*/
void setPowerSaveMode(boolean powerSave);
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
/**
* Returns {@code true} if the device is currently in power save mode.
*/
boolean isPowerSave();
private final ArrayList<BatteryStateChangeCallback> mChangeCallbacks = new ArrayList<>();
private final PowerManager mPowerManager;
private final Handler mHandler;
void addStateChangedCallback(BatteryStateChangeCallback cb);
void removeStateChangedCallback(BatteryStateChangeCallback cb);
private int mLevel;
private boolean mPluggedIn;
private boolean mCharging;
private boolean mCharged;
private boolean mPowerSave;
private boolean mTestmode = false;
public BatteryController(Context context) {
mHandler = new Handler();
mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_BATTERY_CHANGED);
filter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED);
filter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGING);
filter.addAction(ACTION_LEVEL_TEST);
context.registerReceiver(this, filter);
updatePowerSave();
}
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.println("BatteryController state:");
pw.print(" mLevel="); pw.println(mLevel);
pw.print(" mPluggedIn="); pw.println(mPluggedIn);
pw.print(" mCharging="); pw.println(mCharging);
pw.print(" mCharged="); pw.println(mCharged);
pw.print(" mPowerSave="); pw.println(mPowerSave);
}
public void setPowerSaveMode(boolean powerSave) {
mPowerManager.setPowerSaveMode(powerSave);
}
public void addStateChangedCallback(BatteryStateChangeCallback cb) {
mChangeCallbacks.add(cb);
cb.onBatteryLevelChanged(mLevel, mPluggedIn, mCharging);
cb.onPowerSaveChanged(mPowerSave);
}
public void removeStateChangedCallback(BatteryStateChangeCallback cb) {
mChangeCallbacks.remove(cb);
}
public void onReceive(final Context context, Intent intent) {
final String action = intent.getAction();
if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
if (mTestmode && !intent.getBooleanExtra("testmode", false)) return;
mLevel = (int)(100f
* intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0)
/ intent.getIntExtra(BatteryManager.EXTRA_SCALE, 100));
mPluggedIn = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0) != 0;
final int status = intent.getIntExtra(BatteryManager.EXTRA_STATUS,
BatteryManager.BATTERY_STATUS_UNKNOWN);
mCharged = status == BatteryManager.BATTERY_STATUS_FULL;
mCharging = mCharged || status == BatteryManager.BATTERY_STATUS_CHARGING;
fireBatteryLevelChanged();
} else if (action.equals(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED)) {
updatePowerSave();
} else if (action.equals(PowerManager.ACTION_POWER_SAVE_MODE_CHANGING)) {
setPowerSave(intent.getBooleanExtra(PowerManager.EXTRA_POWER_SAVE_MODE, false));
} else if (action.equals(ACTION_LEVEL_TEST)) {
mTestmode = true;
mHandler.post(new Runnable() {
int curLevel = 0;
int incr = 1;
int saveLevel = mLevel;
boolean savePlugged = mPluggedIn;
Intent dummy = new Intent(Intent.ACTION_BATTERY_CHANGED);
@Override
public void run() {
if (curLevel < 0) {
mTestmode = false;
dummy.putExtra("level", saveLevel);
dummy.putExtra("plugged", savePlugged);
dummy.putExtra("testmode", false);
} else {
dummy.putExtra("level", curLevel);
dummy.putExtra("plugged", incr > 0 ? BatteryManager.BATTERY_PLUGGED_AC
: 0);
dummy.putExtra("testmode", true);
}
context.sendBroadcast(dummy);
if (!mTestmode) return;
curLevel += incr;
if (curLevel == 100) {
incr *= -1;
}
mHandler.postDelayed(this, 200);
}
});
}
}
public boolean isPowerSave() {
return mPowerSave;
}
private void updatePowerSave() {
setPowerSave(mPowerManager.isPowerSaveMode());
}
private void setPowerSave(boolean powerSave) {
if (powerSave == mPowerSave) return;
mPowerSave = powerSave;
if (DEBUG) Log.d(TAG, "Power save is " + (mPowerSave ? "on" : "off"));
firePowerSaveChanged();
}
private void fireBatteryLevelChanged() {
final int N = mChangeCallbacks.size();
for (int i = 0; i < N; i++) {
mChangeCallbacks.get(i).onBatteryLevelChanged(mLevel, mPluggedIn, mCharging);
}
}
private void firePowerSaveChanged() {
final int N = mChangeCallbacks.size();
for (int i = 0; i < N; i++) {
mChangeCallbacks.get(i).onPowerSaveChanged(mPowerSave);
}
}
public interface BatteryStateChangeCallback {
/**
* A listener that will be notified whenever a change in battery level or power save mode
* has occurred.
*/
interface BatteryStateChangeCallback {
void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging);
void onPowerSaveChanged(boolean isPowerSave);
}

View File

@@ -0,0 +1,179 @@
/*
* Copyright (C) 2016 The Android Open Source Project
*
* 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.
*/
package com.android.systemui.statusbar.policy;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.BatteryManager;
import android.os.Handler;
import android.os.PowerManager;
import android.util.Log;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
/**
* Default implementation of a {@link BatteryController}. This controller monitors for battery
* level change events that are broadcasted by the system.
*/
public class BatteryControllerImpl extends BroadcastReceiver implements BatteryController {
private static final String TAG = "BatteryController";
public static final String ACTION_LEVEL_TEST = "com.android.systemui.BATTERY_LEVEL_TEST";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
private final ArrayList<BatteryController.BatteryStateChangeCallback> mChangeCallbacks = new ArrayList<>();
private final PowerManager mPowerManager;
private final Handler mHandler;
protected int mLevel;
protected boolean mPluggedIn;
protected boolean mCharging;
protected boolean mCharged;
protected boolean mPowerSave;
private boolean mTestmode = false;
public BatteryControllerImpl(Context context) {
mHandler = new Handler();
mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_BATTERY_CHANGED);
filter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED);
filter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGING);
filter.addAction(ACTION_LEVEL_TEST);
context.registerReceiver(this, filter);
updatePowerSave();
}
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.println("BatteryController state:");
pw.print(" mLevel="); pw.println(mLevel);
pw.print(" mPluggedIn="); pw.println(mPluggedIn);
pw.print(" mCharging="); pw.println(mCharging);
pw.print(" mCharged="); pw.println(mCharged);
pw.print(" mPowerSave="); pw.println(mPowerSave);
}
@Override
public void setPowerSaveMode(boolean powerSave) {
mPowerManager.setPowerSaveMode(powerSave);
}
@Override
public void addStateChangedCallback(BatteryController.BatteryStateChangeCallback cb) {
mChangeCallbacks.add(cb);
cb.onBatteryLevelChanged(mLevel, mPluggedIn, mCharging);
cb.onPowerSaveChanged(mPowerSave);
}
@Override
public void removeStateChangedCallback(BatteryController.BatteryStateChangeCallback cb) {
mChangeCallbacks.remove(cb);
}
@Override
public void onReceive(final Context context, Intent intent) {
final String action = intent.getAction();
if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
if (mTestmode && !intent.getBooleanExtra("testmode", false)) return;
mLevel = (int)(100f
* intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0)
/ intent.getIntExtra(BatteryManager.EXTRA_SCALE, 100));
mPluggedIn = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0) != 0;
final int status = intent.getIntExtra(BatteryManager.EXTRA_STATUS,
BatteryManager.BATTERY_STATUS_UNKNOWN);
mCharged = status == BatteryManager.BATTERY_STATUS_FULL;
mCharging = mCharged || status == BatteryManager.BATTERY_STATUS_CHARGING;
fireBatteryLevelChanged();
} else if (action.equals(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED)) {
updatePowerSave();
} else if (action.equals(PowerManager.ACTION_POWER_SAVE_MODE_CHANGING)) {
setPowerSave(intent.getBooleanExtra(PowerManager.EXTRA_POWER_SAVE_MODE, false));
} else if (action.equals(ACTION_LEVEL_TEST)) {
mTestmode = true;
mHandler.post(new Runnable() {
int curLevel = 0;
int incr = 1;
int saveLevel = mLevel;
boolean savePlugged = mPluggedIn;
Intent dummy = new Intent(Intent.ACTION_BATTERY_CHANGED);
@Override
public void run() {
if (curLevel < 0) {
mTestmode = false;
dummy.putExtra("level", saveLevel);
dummy.putExtra("plugged", savePlugged);
dummy.putExtra("testmode", false);
} else {
dummy.putExtra("level", curLevel);
dummy.putExtra("plugged", incr > 0 ? BatteryManager.BATTERY_PLUGGED_AC
: 0);
dummy.putExtra("testmode", true);
}
context.sendBroadcast(dummy);
if (!mTestmode) return;
curLevel += incr;
if (curLevel == 100) {
incr *= -1;
}
mHandler.postDelayed(this, 200);
}
});
}
}
@Override
public boolean isPowerSave() {
return mPowerSave;
}
private void updatePowerSave() {
setPowerSave(mPowerManager.isPowerSaveMode());
}
private void setPowerSave(boolean powerSave) {
if (powerSave == mPowerSave) return;
mPowerSave = powerSave;
if (DEBUG) Log.d(TAG, "Power save is " + (mPowerSave ? "on" : "off"));
firePowerSaveChanged();
}
protected void fireBatteryLevelChanged() {
final int N = mChangeCallbacks.size();
for (int i = 0; i < N; i++) {
mChangeCallbacks.get(i).onBatteryLevelChanged(mLevel, mPluggedIn, mCharging);
}
}
private void firePowerSaveChanged() {
final int N = mChangeCallbacks.size();
for (int i = 0; i < N; i++) {
mChangeCallbacks.get(i).onPowerSaveChanged(mPowerSave);
}
}
}