Home | History | Annotate | Download | only in policy
      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 addStateChangedCallback(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 removeStateChangedCallback(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            if (level != null) {
    213                mLevel = Math.min(Math.max(Integer.parseInt(level), 0), 100);
    214            }
    215            if (plugged != null) {
    216                mPluggedIn = Boolean.parseBoolean(plugged);
    217            }
    218             fireBatteryLevelChanged();
    219         }
    220     }
    221 }
    222