Merge "For Auto, display battery status as that of a connected device." into nyc-dev

This commit is contained in:
Anthony Chen
2016-04-11 02:51:56 +00:00
committed by Android (Google) Code Review
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);
}
}
}