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 17package com.android.systemui.statusbar.policy; 18 19import android.content.BroadcastReceiver; 20import android.content.Context; 21import android.content.Intent; 22import android.content.IntentFilter; 23import android.os.BatteryManager; 24import android.os.Bundle; 25import android.os.Handler; 26import android.os.PowerManager; 27import android.util.Log; 28import com.android.systemui.DemoMode; 29 30import java.io.FileDescriptor; 31import java.io.PrintWriter; 32import 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 */ 38public 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 57 public BatteryControllerImpl(Context context) { 58 mContext = context; 59 mHandler = new Handler(); 60 mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE); 61 62 registerReceiver(); 63 updatePowerSave(); 64 } 65 66 private void registerReceiver() { 67 IntentFilter filter = new IntentFilter(); 68 filter.addAction(Intent.ACTION_BATTERY_CHANGED); 69 filter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED); 70 filter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGING); 71 filter.addAction(ACTION_LEVEL_TEST); 72 mContext.registerReceiver(this, filter); 73 } 74 75 @Override 76 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 77 pw.println("BatteryController state:"); 78 pw.print(" mLevel="); pw.println(mLevel); 79 pw.print(" mPluggedIn="); pw.println(mPluggedIn); 80 pw.print(" mCharging="); pw.println(mCharging); 81 pw.print(" mCharged="); pw.println(mCharged); 82 pw.print(" mPowerSave="); pw.println(mPowerSave); 83 } 84 85 @Override 86 public void setPowerSaveMode(boolean powerSave) { 87 mPowerManager.setPowerSaveMode(powerSave); 88 } 89 90 @Override 91 public void addStateChangedCallback(BatteryController.BatteryStateChangeCallback cb) { 92 mChangeCallbacks.add(cb); 93 cb.onBatteryLevelChanged(mLevel, mPluggedIn, mCharging); 94 cb.onPowerSaveChanged(mPowerSave); 95 } 96 97 @Override 98 public void removeStateChangedCallback(BatteryController.BatteryStateChangeCallback cb) { 99 mChangeCallbacks.remove(cb); 100 } 101 102 @Override 103 public void onReceive(final Context context, Intent intent) { 104 final String action = intent.getAction(); 105 if (action.equals(Intent.ACTION_BATTERY_CHANGED)) { 106 if (mTestmode && !intent.getBooleanExtra("testmode", false)) return; 107 mLevel = (int)(100f 108 * intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0) 109 / intent.getIntExtra(BatteryManager.EXTRA_SCALE, 100)); 110 mPluggedIn = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0) != 0; 111 112 final int status = intent.getIntExtra(BatteryManager.EXTRA_STATUS, 113 BatteryManager.BATTERY_STATUS_UNKNOWN); 114 mCharged = status == BatteryManager.BATTERY_STATUS_FULL; 115 mCharging = mCharged || status == BatteryManager.BATTERY_STATUS_CHARGING; 116 117 fireBatteryLevelChanged(); 118 } else if (action.equals(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED)) { 119 updatePowerSave(); 120 } else if (action.equals(PowerManager.ACTION_POWER_SAVE_MODE_CHANGING)) { 121 setPowerSave(intent.getBooleanExtra(PowerManager.EXTRA_POWER_SAVE_MODE, false)); 122 } else if (action.equals(ACTION_LEVEL_TEST)) { 123 mTestmode = true; 124 mHandler.post(new Runnable() { 125 int curLevel = 0; 126 int incr = 1; 127 int saveLevel = mLevel; 128 boolean savePlugged = mPluggedIn; 129 Intent dummy = new Intent(Intent.ACTION_BATTERY_CHANGED); 130 @Override 131 public void run() { 132 if (curLevel < 0) { 133 mTestmode = false; 134 dummy.putExtra("level", saveLevel); 135 dummy.putExtra("plugged", savePlugged); 136 dummy.putExtra("testmode", false); 137 } else { 138 dummy.putExtra("level", curLevel); 139 dummy.putExtra("plugged", incr > 0 ? BatteryManager.BATTERY_PLUGGED_AC 140 : 0); 141 dummy.putExtra("testmode", true); 142 } 143 context.sendBroadcast(dummy); 144 145 if (!mTestmode) return; 146 147 curLevel += incr; 148 if (curLevel == 100) { 149 incr *= -1; 150 } 151 mHandler.postDelayed(this, 200); 152 } 153 }); 154 } 155 } 156 157 @Override 158 public boolean isPowerSave() { 159 return mPowerSave; 160 } 161 162 private void updatePowerSave() { 163 setPowerSave(mPowerManager.isPowerSaveMode()); 164 } 165 166 private void setPowerSave(boolean powerSave) { 167 if (powerSave == mPowerSave) return; 168 mPowerSave = powerSave; 169 if (DEBUG) Log.d(TAG, "Power save is " + (mPowerSave ? "on" : "off")); 170 firePowerSaveChanged(); 171 } 172 173 protected void fireBatteryLevelChanged() { 174 final int N = mChangeCallbacks.size(); 175 for (int i = 0; i < N; i++) { 176 mChangeCallbacks.get(i).onBatteryLevelChanged(mLevel, mPluggedIn, mCharging); 177 } 178 } 179 180 private void firePowerSaveChanged() { 181 final int N = mChangeCallbacks.size(); 182 for (int i = 0; i < N; i++) { 183 mChangeCallbacks.get(i).onPowerSaveChanged(mPowerSave); 184 } 185 } 186 187 private boolean mDemoMode; 188 189 @Override 190 public void dispatchDemoCommand(String command, Bundle args) { 191 if (!mDemoMode && command.equals(COMMAND_ENTER)) { 192 mDemoMode = true; 193 mContext.unregisterReceiver(this); 194 } else if (mDemoMode && command.equals(COMMAND_EXIT)) { 195 mDemoMode = false; 196 registerReceiver(); 197 updatePowerSave(); 198 } else if (mDemoMode && command.equals(COMMAND_BATTERY)) { 199 String level = args.getString("level"); 200 String plugged = args.getString("plugged"); 201 if (level != null) { 202 mLevel = Math.min(Math.max(Integer.parseInt(level), 0), 100); 203 } 204 if (plugged != null) { 205 mPluggedIn = Boolean.parseBoolean(plugged); 206 } 207 fireBatteryLevelChanged(); 208 } 209 } 210} 211