1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.systemui.statusbar.policy; 18 19 import android.content.BroadcastReceiver; 20 import android.content.Context; 21 import android.content.Intent; 22 import android.content.IntentFilter; 23 import android.os.BatteryManager; 24 import android.os.Bundle; 25 import android.os.Handler; 26 import android.os.PowerManager; 27 import android.util.Log; 28 import com.android.systemui.DemoMode; 29 30 import java.io.FileDescriptor; 31 import java.io.PrintWriter; 32 import java.util.ArrayList; 33 34 /** 35 * Default implementation of a {@link BatteryController}. This controller monitors for battery 36 * level change events that are broadcasted by the system. 37 */ 38 public class BatteryControllerImpl extends BroadcastReceiver implements BatteryController { 39 private static final String TAG = "BatteryController"; 40 41 public static final String ACTION_LEVEL_TEST = "com.android.systemui.BATTERY_LEVEL_TEST"; 42 43 private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); 44 45 private final ArrayList<BatteryController.BatteryStateChangeCallback> mChangeCallbacks = new ArrayList<>(); 46 private final PowerManager mPowerManager; 47 private final Handler mHandler; 48 private final Context mContext; 49 50 protected int mLevel; 51 protected boolean mPluggedIn; 52 protected boolean mCharging; 53 protected boolean mCharged; 54 protected boolean mPowerSave; 55 private boolean mTestmode = false; 56 private boolean mHasReceivedBattery = false; 57 58 public BatteryControllerImpl(Context context) { 59 mContext = context; 60 mHandler = new Handler(); 61 mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE); 62 63 registerReceiver(); 64 updatePowerSave(); 65 } 66 67 private void registerReceiver() { 68 IntentFilter filter = new IntentFilter(); 69 filter.addAction(Intent.ACTION_BATTERY_CHANGED); 70 filter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED); 71 filter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGING); 72 filter.addAction(ACTION_LEVEL_TEST); 73 mContext.registerReceiver(this, filter); 74 } 75 76 @Override 77 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 78 pw.println("BatteryController state:"); 79 pw.print(" mLevel="); pw.println(mLevel); 80 pw.print(" mPluggedIn="); pw.println(mPluggedIn); 81 pw.print(" mCharging="); pw.println(mCharging); 82 pw.print(" mCharged="); pw.println(mCharged); 83 pw.print(" mPowerSave="); pw.println(mPowerSave); 84 } 85 86 @Override 87 public void setPowerSaveMode(boolean powerSave) { 88 mPowerManager.setPowerSaveMode(powerSave); 89 } 90 91 @Override 92 public void addCallback(BatteryController.BatteryStateChangeCallback cb) { 93 synchronized (mChangeCallbacks) { 94 mChangeCallbacks.add(cb); 95 } 96 if (!mHasReceivedBattery) return; 97 cb.onBatteryLevelChanged(mLevel, mPluggedIn, mCharging); 98 cb.onPowerSaveChanged(mPowerSave); 99 } 100 101 @Override 102 public void removeCallback(BatteryController.BatteryStateChangeCallback cb) { 103 synchronized (mChangeCallbacks) { 104 mChangeCallbacks.remove(cb); 105 } 106 } 107 108 @Override 109 public void onReceive(final Context context, Intent intent) { 110 final String action = intent.getAction(); 111 if (action.equals(Intent.ACTION_BATTERY_CHANGED)) { 112 if (mTestmode && !intent.getBooleanExtra("testmode", false)) return; 113 mHasReceivedBattery = true; 114 mLevel = (int)(100f 115 * intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0) 116 / intent.getIntExtra(BatteryManager.EXTRA_SCALE, 100)); 117 mPluggedIn = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0) != 0; 118 119 final int status = intent.getIntExtra(BatteryManager.EXTRA_STATUS, 120 BatteryManager.BATTERY_STATUS_UNKNOWN); 121 mCharged = status == BatteryManager.BATTERY_STATUS_FULL; 122 mCharging = mCharged || status == BatteryManager.BATTERY_STATUS_CHARGING; 123 124 fireBatteryLevelChanged(); 125 } else if (action.equals(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED)) { 126 updatePowerSave(); 127 } else if (action.equals(PowerManager.ACTION_POWER_SAVE_MODE_CHANGING)) { 128 setPowerSave(intent.getBooleanExtra(PowerManager.EXTRA_POWER_SAVE_MODE, false)); 129 } else if (action.equals(ACTION_LEVEL_TEST)) { 130 mTestmode = true; 131 mHandler.post(new Runnable() { 132 int curLevel = 0; 133 int incr = 1; 134 int saveLevel = mLevel; 135 boolean savePlugged = mPluggedIn; 136 Intent dummy = new Intent(Intent.ACTION_BATTERY_CHANGED); 137 @Override 138 public void run() { 139 if (curLevel < 0) { 140 mTestmode = false; 141 dummy.putExtra("level", saveLevel); 142 dummy.putExtra("plugged", savePlugged); 143 dummy.putExtra("testmode", false); 144 } else { 145 dummy.putExtra("level", curLevel); 146 dummy.putExtra("plugged", incr > 0 ? BatteryManager.BATTERY_PLUGGED_AC 147 : 0); 148 dummy.putExtra("testmode", true); 149 } 150 context.sendBroadcast(dummy); 151 152 if (!mTestmode) return; 153 154 curLevel += incr; 155 if (curLevel == 100) { 156 incr *= -1; 157 } 158 mHandler.postDelayed(this, 200); 159 } 160 }); 161 } 162 } 163 164 @Override 165 public boolean isPowerSave() { 166 return mPowerSave; 167 } 168 169 private void updatePowerSave() { 170 setPowerSave(mPowerManager.isPowerSaveMode()); 171 } 172 173 private void setPowerSave(boolean powerSave) { 174 if (powerSave == mPowerSave) return; 175 mPowerSave = powerSave; 176 if (DEBUG) Log.d(TAG, "Power save is " + (mPowerSave ? "on" : "off")); 177 firePowerSaveChanged(); 178 } 179 180 protected void fireBatteryLevelChanged() { 181 synchronized (mChangeCallbacks) { 182 final int N = mChangeCallbacks.size(); 183 for (int i = 0; i < N; i++) { 184 mChangeCallbacks.get(i).onBatteryLevelChanged(mLevel, mPluggedIn, mCharging); 185 } 186 } 187 } 188 189 private void firePowerSaveChanged() { 190 synchronized (mChangeCallbacks) { 191 final int N = mChangeCallbacks.size(); 192 for (int i = 0; i < N; i++) { 193 mChangeCallbacks.get(i).onPowerSaveChanged(mPowerSave); 194 } 195 } 196 } 197 198 private boolean mDemoMode; 199 200 @Override 201 public void dispatchDemoCommand(String command, Bundle args) { 202 if (!mDemoMode && command.equals(COMMAND_ENTER)) { 203 mDemoMode = true; 204 mContext.unregisterReceiver(this); 205 } else if (mDemoMode && command.equals(COMMAND_EXIT)) { 206 mDemoMode = false; 207 registerReceiver(); 208 updatePowerSave(); 209 } else if (mDemoMode && command.equals(COMMAND_BATTERY)) { 210 String level = args.getString("level"); 211 String plugged = args.getString("plugged"); 212 String powerSave = args.getString("powersave"); 213 if (level != null) { 214 mLevel = Math.min(Math.max(Integer.parseInt(level), 0), 100); 215 } 216 if (plugged != null) { 217 mPluggedIn = Boolean.parseBoolean(plugged); 218 } 219 if (powerSave != null) { 220 mPowerSave = powerSave.equals("true"); 221 firePowerSaveChanged(); 222 } 223 fireBatteryLevelChanged(); 224 } 225 } 226 } 227