1 /*
2  * Copyright (C) 2017 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.settings.fuelgauge;
18 
19 import android.content.BroadcastReceiver;
20 import android.content.Context;
21 import android.content.Intent;
22 import android.content.IntentFilter;
23 import android.hardware.usb.UsbManager;
24 import android.os.BatteryManager;
25 import android.os.PowerManager;
26 import android.util.Log;
27 
28 import androidx.annotation.IntDef;
29 import androidx.annotation.VisibleForTesting;
30 
31 import com.android.settings.Utils;
32 
33 import java.lang.annotation.Retention;
34 import java.lang.annotation.RetentionPolicy;
35 
36 /**
37  * Use this broadcastReceiver to listen to the battery change and it will invoke {@link
38  * OnBatteryChangedListener}
39  */
40 public class BatteryBroadcastReceiver extends BroadcastReceiver {
41 
42     private static final String TAG = "BatteryBroadcastRcvr";
43 
44     /**
45      * Callback if any of the monitored fields has been changed: <br>
46      * <br>
47      * Battery level(e.g. 100%->99%) Battery status(e.g. plugged->unplugged) <br>
48      * Battery saver(e.g.off->on) <br>
49      * Battery health(e.g. good->overheat) <br>
50      * Battery charging status(e.g. default->long life)
51      */
52     public interface OnBatteryChangedListener {
onBatteryChanged(@atteryUpdateType int type)53         void onBatteryChanged(@BatteryUpdateType int type);
54     }
55 
56     @Retention(RetentionPolicy.SOURCE)
57     @IntDef({
58         BatteryUpdateType.MANUAL,
59         BatteryUpdateType.BATTERY_LEVEL,
60         BatteryUpdateType.BATTERY_SAVER,
61         BatteryUpdateType.BATTERY_STATUS,
62         BatteryUpdateType.BATTERY_HEALTH,
63         BatteryUpdateType.CHARGING_STATUS,
64         BatteryUpdateType.BATTERY_NOT_PRESENT
65     })
66     public @interface BatteryUpdateType {
67         int MANUAL = 0;
68         int BATTERY_LEVEL = 1;
69         int BATTERY_SAVER = 2;
70         int BATTERY_STATUS = 3;
71         int BATTERY_HEALTH = 4;
72         int CHARGING_STATUS = 5;
73         int BATTERY_NOT_PRESENT = 6;
74     }
75 
76     @VisibleForTesting String mBatteryLevel;
77     @VisibleForTesting String mBatteryStatus;
78     @VisibleForTesting int mChargingStatus;
79     @VisibleForTesting int mBatteryHealth;
80     private OnBatteryChangedListener mBatteryListener;
81     private Context mContext;
82 
BatteryBroadcastReceiver(Context context)83     public BatteryBroadcastReceiver(Context context) {
84         mContext = context;
85     }
86 
87     @Override
onReceive(Context context, Intent intent)88     public void onReceive(Context context, Intent intent) {
89         updateBatteryStatus(intent, false /* forceUpdate */);
90     }
91 
setBatteryChangedListener(OnBatteryChangedListener lsn)92     public void setBatteryChangedListener(OnBatteryChangedListener lsn) {
93         mBatteryListener = lsn;
94     }
95 
register()96     public void register() {
97         final IntentFilter intentFilter = new IntentFilter();
98         intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED);
99         intentFilter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED);
100         intentFilter.addAction(BatteryUtils.BYPASS_DOCK_DEFENDER_ACTION);
101         intentFilter.addAction(UsbManager.ACTION_USB_PORT_COMPLIANCE_CHANGED);
102 
103         final Intent intent =
104                 mContext.registerReceiver(this, intentFilter, Context.RECEIVER_EXPORTED);
105         updateBatteryStatus(intent, true /* forceUpdate */);
106     }
107 
unRegister()108     public void unRegister() {
109         mContext.unregisterReceiver(this);
110     }
111 
updateBatteryStatus(Intent intent, boolean forceUpdate)112     private void updateBatteryStatus(Intent intent, boolean forceUpdate) {
113         if (intent == null || mBatteryListener == null) {
114             return;
115         }
116         final String action = intent.getAction();
117         Log.d(TAG, "updateBatteryStatus: action=" + action);
118         if (Intent.ACTION_BATTERY_CHANGED.equals(action)) {
119             final String batteryLevel = Utils.getBatteryPercentage(intent);
120             final String batteryStatus =
121                     Utils.getBatteryStatus(mContext, intent, /* compactStatus= */ false);
122             final int chargingStatus =
123                     intent.getIntExtra(
124                             BatteryManager.EXTRA_CHARGING_STATUS,
125                             BatteryManager.CHARGING_POLICY_DEFAULT);
126             final int batteryHealth =
127                     intent.getIntExtra(
128                             BatteryManager.EXTRA_HEALTH, BatteryManager.BATTERY_HEALTH_UNKNOWN);
129             Log.d(
130                     TAG,
131                     "Battery changed: level: "
132                             + batteryLevel
133                             + "| status: "
134                             + batteryStatus
135                             + "| chargingStatus: "
136                             + chargingStatus
137                             + "| health: "
138                             + batteryHealth);
139             if (!Utils.isBatteryPresent(intent)) {
140                 Log.w(TAG, "Problem reading the battery meter.");
141                 mBatteryListener.onBatteryChanged(BatteryUpdateType.BATTERY_NOT_PRESENT);
142             } else if (forceUpdate) {
143                 mBatteryListener.onBatteryChanged(BatteryUpdateType.MANUAL);
144             } else if (chargingStatus != mChargingStatus) {
145                 mBatteryListener.onBatteryChanged(BatteryUpdateType.CHARGING_STATUS);
146             } else if (batteryHealth != mBatteryHealth) {
147                 mBatteryListener.onBatteryChanged(BatteryUpdateType.BATTERY_HEALTH);
148             } else if (!batteryLevel.equals(mBatteryLevel)) {
149                 mBatteryListener.onBatteryChanged(BatteryUpdateType.BATTERY_LEVEL);
150             } else if (!batteryStatus.equals(mBatteryStatus)) {
151                 mBatteryListener.onBatteryChanged(BatteryUpdateType.BATTERY_STATUS);
152             }
153             mBatteryLevel = batteryLevel;
154             mBatteryStatus = batteryStatus;
155             mChargingStatus = chargingStatus;
156             mBatteryHealth = batteryHealth;
157         } else if (PowerManager.ACTION_POWER_SAVE_MODE_CHANGED.equals(action)) {
158             mBatteryListener.onBatteryChanged(BatteryUpdateType.BATTERY_SAVER);
159         } else if (BatteryUtils.BYPASS_DOCK_DEFENDER_ACTION.equals(action)
160                 || UsbManager.ACTION_USB_PORT_COMPLIANCE_CHANGED.equals(action)) {
161             mBatteryListener.onBatteryChanged(BatteryUpdateType.BATTERY_STATUS);
162         }
163     }
164 }
165