Merge "Add incompatible charging state on the lockscreen"

This commit is contained in:
YK Hung
2023-02-14 14:36:54 +00:00
committed by Android (Google) Code Review
5 changed files with 157 additions and 16 deletions

View File

@@ -34,6 +34,8 @@ import android.os.BatteryManager;
import com.android.settingslib.R;
import java.util.Optional;
/**
* Stores and computes some battery information.
*/
@@ -52,11 +54,12 @@ public class BatteryStatus {
public final int health;
public final int maxChargingWattage;
public final boolean present;
public final Optional<Boolean> incompatibleCharger;
public static BatteryStatus create(Context context) {
public static BatteryStatus create(Context context, boolean incompatibleCharger) {
final Intent batteryChangedIntent = BatteryUtils.getBatteryIntent(context);
return batteryChangedIntent == null
? null : new BatteryStatus(batteryChangedIntent);
? null : new BatteryStatus(batteryChangedIntent, incompatibleCharger);
}
public BatteryStatus(int status, int level, int plugged, int health,
@@ -67,14 +70,25 @@ public class BatteryStatus {
this.health = health;
this.maxChargingWattage = maxChargingWattage;
this.present = present;
this.incompatibleCharger = Optional.empty();
}
public BatteryStatus(Intent batteryChangedIntent) {
this(batteryChangedIntent, Optional.empty());
}
public BatteryStatus(Intent batteryChangedIntent, boolean incompatibleCharger) {
this(batteryChangedIntent, Optional.of(incompatibleCharger));
}
private BatteryStatus(Intent batteryChangedIntent, Optional<Boolean> incompatibleCharger) {
status = batteryChangedIntent.getIntExtra(EXTRA_STATUS, BATTERY_STATUS_UNKNOWN);
plugged = batteryChangedIntent.getIntExtra(EXTRA_PLUGGED, 0);
level = getBatteryLevel(batteryChangedIntent);
health = batteryChangedIntent.getIntExtra(EXTRA_HEALTH, BATTERY_HEALTH_UNKNOWN);
present = batteryChangedIntent.getBooleanExtra(EXTRA_PRESENT, true);
this.incompatibleCharger = incompatibleCharger;
final int maxChargingMicroAmp = batteryChangedIntent.getIntExtra(EXTRA_MAX_CHARGING_CURRENT,
-1);
@@ -95,10 +109,7 @@ public class BatteryStatus {
/** Determine whether the device is plugged. */
public boolean isPluggedIn() {
return plugged == BatteryManager.BATTERY_PLUGGED_AC
|| plugged == BatteryManager.BATTERY_PLUGGED_USB
|| plugged == BatteryManager.BATTERY_PLUGGED_WIRELESS
|| plugged == BatteryManager.BATTERY_PLUGGED_DOCK;
return isPluggedIn(plugged);
}
/** Determine whether the device is plugged in (USB, power). */
@@ -190,4 +201,17 @@ public class BatteryStatus {
? -1 /*invalid battery level*/
: Math.round((level / (float) scale) * 100f);
}
/** Whether the device is plugged or not. */
public static boolean isPluggedIn(Intent batteryChangedIntent) {
return isPluggedIn(batteryChangedIntent.getIntExtra(EXTRA_PLUGGED, 0));
}
/** Whether the device is plugged or not. */
public static boolean isPluggedIn(int plugged) {
return plugged == BatteryManager.BATTERY_PLUGGED_AC
|| plugged == BatteryManager.BATTERY_PLUGGED_USB
|| plugged == BatteryManager.BATTERY_PLUGGED_WIRELESS
|| plugged == BatteryManager.BATTERY_PLUGGED_DOCK;
}
}

View File

@@ -55,6 +55,9 @@
<!-- When the lock screen is showing and the phone plugged in, and the defend mode is triggered, say that charging is temporarily limited. -->
<string name="keyguard_plugged_in_charging_limited"><xliff:g id="percentage">%s</xliff:g> • Charging optimized to protect battery</string>
<!-- When the lock screen is showing and the phone plugged in with incompatible charger. -->
<string name="keyguard_plugged_in_incompatible_charger"><xliff:g id="percentage">%s</xliff:g> • Incompatible charging</string>
<!-- On the keyguard screen, when pattern lock is disabled, only tell them to press menu to unlock. This is shown in small font at the bottom. -->
<string name="keyguard_instructions_when_pattern_disabled">Press Menu to unlock.</string>

View File

@@ -102,6 +102,7 @@ import android.hardware.fingerprint.FingerprintManager;
import android.hardware.fingerprint.FingerprintManager.AuthenticationCallback;
import android.hardware.fingerprint.FingerprintManager.AuthenticationResult;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.hardware.usb.UsbManager;
import android.nfc.NfcAdapter;
import android.os.CancellationSignal;
import android.os.Handler;
@@ -138,6 +139,7 @@ import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.logging.KeyguardUpdateMonitorLogger;
import com.android.settingslib.WirelessUtils;
import com.android.settingslib.fuelgauge.BatteryStatus;
import com.android.settingslib.Utils;
import com.android.systemui.Dumpable;
import com.android.systemui.R;
import com.android.systemui.biometrics.AuthController;
@@ -329,6 +331,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
// Battery status
@VisibleForTesting
BatteryStatus mBatteryStatus;
@VisibleForTesting
boolean mIncompatibleCharger;
private StrongAuthTracker mStrongAuthTracker;
@@ -1572,10 +1576,20 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
MSG_TIMEZONE_UPDATE, intent.getStringExtra(Intent.EXTRA_TIMEZONE));
mHandler.sendMessage(msg);
} else if (Intent.ACTION_BATTERY_CHANGED.equals(action)) {
// Clear incompatible charger state when device is unplugged.
if (!BatteryStatus.isPluggedIn(intent)) {
mIncompatibleCharger = false;
}
final Message msg = mHandler.obtainMessage(
MSG_BATTERY_UPDATE, new BatteryStatus(intent));
MSG_BATTERY_UPDATE, new BatteryStatus(intent, mIncompatibleCharger));
mHandler.sendMessage(msg);
} else if (UsbManager.ACTION_USB_PORT_COMPLIANCE_CHANGED.equals(action)) {
mIncompatibleCharger = Utils.containsIncompatibleChargers(context, TAG);
BatteryStatus batteryStatus = BatteryStatus.create(context, mIncompatibleCharger);
if (batteryStatus != null) {
mHandler.sendMessage(
mHandler.obtainMessage(MSG_BATTERY_UPDATE, batteryStatus));
}
} else if (Intent.ACTION_SIM_STATE_CHANGED.equals(action)) {
SimData args = SimData.fromIntent(intent);
// ACTION_SIM_STATE_CHANGED is rebroadcast after unlocking the device to
@@ -2251,6 +2265,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
filter.addAction(TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED);
filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
filter.addAction(UsbManager.ACTION_USB_PORT_COMPLIANCE_CHANGED);
mBroadcastDispatcher.registerReceiverWithHandler(mBroadcastReceiver, filter, mHandler);
// Since ACTION_SERVICE_STATE is being moved to a non-sticky broadcast, trigger the
// listener now with the service state from the default sub.
@@ -3527,8 +3542,6 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
final boolean wasPluggedIn = old.isPluggedIn();
final boolean stateChangedWhilePluggedIn = wasPluggedIn && nowPluggedIn
&& (old.status != current.status);
final boolean nowPresent = current.present;
final boolean wasPresent = old.present;
// change in plug state is always interesting
if (wasPluggedIn != nowPluggedIn || stateChangedWhilePluggedIn) {
@@ -3545,8 +3558,13 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
return true;
}
// Battery either showed up or disappeared
if (wasPresent != nowPresent) {
// change in battery is present or not
if (old.present != current.present) {
return true;
}
// change in the incompatible charger
if (!old.incompatibleCharger.equals(current.incompatibleCharger)) {
return true;
}

View File

@@ -185,6 +185,7 @@ public class KeyguardIndicationController {
private boolean mPowerCharged;
private boolean mBatteryOverheated;
private boolean mEnableBatteryDefender;
private boolean mIncompatibleCharger;
private int mChargingSpeed;
private int mChargingWattage;
private int mBatteryLevel;
@@ -903,6 +904,10 @@ public class KeyguardIndicationController {
chargingId = R.string.keyguard_plugged_in_charging_limited;
String percentage = NumberFormat.getPercentInstance().format(mBatteryLevel / 100f);
return mContext.getResources().getString(chargingId, percentage);
} else if (mPowerPluggedIn && mIncompatibleCharger) {
chargingId = R.string.keyguard_plugged_in_incompatible_charger;
String percentage = NumberFormat.getPercentInstance().format(mBatteryLevel / 100f);
return mContext.getResources().getString(chargingId, percentage);
} else if (mPowerCharged) {
return mContext.getResources().getString(R.string.keyguard_charged);
}
@@ -1063,6 +1068,7 @@ public class KeyguardIndicationController {
mBatteryPresent = status.present;
mBatteryOverheated = status.isOverheated();
mEnableBatteryDefender = mBatteryOverheated && status.isPluggedIn();
mIncompatibleCharger = status.incompatibleCharger.orElse(false);
try {
mChargingTimeRemaining = mPowerPluggedIn
? mBatteryInfo.computeChargeTimeRemaining() : -1;

View File

@@ -85,8 +85,12 @@ import android.hardware.face.FaceSensorPropertiesInternal;
import android.hardware.fingerprint.FingerprintManager;
import android.hardware.fingerprint.FingerprintSensorProperties;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.hardware.usb.UsbManager;
import android.hardware.usb.UsbPort;
import android.hardware.usb.UsbPortStatus;
import android.net.Uri;
import android.nfc.NfcAdapter;
import android.os.BatteryManager;
import android.os.Bundle;
import android.os.CancellationSignal;
import android.os.Handler;
@@ -117,6 +121,7 @@ import com.android.internal.widget.ILockSettings;
import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.KeyguardUpdateMonitor.BiometricAuthenticated;
import com.android.keyguard.logging.KeyguardUpdateMonitorLogger;
import com.android.settingslib.fuelgauge.BatteryStatus;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.biometrics.AuthController;
import com.android.systemui.biometrics.FingerprintInteractiveToAuthProvider;
@@ -238,9 +243,16 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
private UiEventLogger mUiEventLogger;
@Mock
private GlobalSettings mGlobalSettings;
private FaceWakeUpTriggersConfig mFaceWakeUpTriggersConfig;
@Mock
private FingerprintInteractiveToAuthProvider mInteractiveToAuthProvider;
@Mock
private UsbPort mUsbPort;
@Mock
private UsbManager mUsbManager;
@Mock
private UsbPortStatus mUsbPortStatus;
@Mock
private Uri mURI;
private List<FingerprintSensorPropertiesInternal> mFingerprintSensorProperties;
private final int mCurrentUserId = 100;
@@ -252,9 +264,6 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
@Captor
private ArgumentCaptor<FaceManager.AuthenticationCallback> mAuthenticationCallbackCaptor;
@Mock
private Uri mURI;
// Direct executor
private final Executor mBackgroundExecutor = Runnable::run;
private final Executor mMainExecutor = Runnable::run;
@@ -264,6 +273,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
private MockitoSession mMockitoSession;
private StatusBarStateController.StateListener mStatusBarStateListener;
private IBiometricEnabledOnKeyguardCallback mBiometricEnabledOnKeyguardCallback;
private FaceWakeUpTriggersConfig mFaceWakeUpTriggersConfig;
private final InstanceId mKeyguardInstanceId = InstanceId.fakeInstanceId(999);
@Before
@@ -2373,6 +2383,55 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
assertThat(mKeyguardUpdateMonitor.shouldListenForFace()).isTrue();
}
@Test
public void testBatteryChangedIntent_refreshBatteryInfo() {
mKeyguardUpdateMonitor.mBroadcastReceiver.onReceive(mContext, getBatteryIntent());
BatteryStatus status = verifyRefreshBatteryInfo();
assertThat(status.incompatibleCharger.get()).isFalse();
assertThat(mKeyguardUpdateMonitor.mIncompatibleCharger).isFalse();
}
@Test
public void testUsbComplianceIntent_refreshBatteryInfo() {
Context contextSpy = getSpyContext();
when(contextSpy.registerReceiver(eq(null), any(IntentFilter.class)))
.thenReturn(getBatteryIntent());
mKeyguardUpdateMonitor.mBroadcastReceiver.onReceive(
contextSpy, new Intent(UsbManager.ACTION_USB_PORT_COMPLIANCE_CHANGED));
mTestableLooper.processAllMessages();
assertThat(mKeyguardUpdateMonitor.mIncompatibleCharger).isFalse();
}
@Test
public void testUsbComplianceIntent_refreshBatteryInfoWithIncompatibleCharger() {
Context contextSpy = getSpyContext();
setupIncompatibleCharging();
when(contextSpy.registerReceiver(eq(null), any(IntentFilter.class)))
.thenReturn(getBatteryIntent());
mKeyguardUpdateMonitor.mBroadcastReceiver.onReceive(
contextSpy, new Intent(UsbManager.ACTION_USB_PORT_COMPLIANCE_CHANGED));
mTestableLooper.processAllMessages();
assertThat(mKeyguardUpdateMonitor.mIncompatibleCharger).isTrue();
}
@Test
public void testBatteryChangedIntent_unplugDevice_resetIncompatibleCharger() {
mKeyguardUpdateMonitor.mIncompatibleCharger = true;
Intent batteryChangedIntent =
getBatteryIntent().putExtra(BatteryManager.EXTRA_PLUGGED, -1);
mKeyguardUpdateMonitor.mBroadcastReceiver.onReceive(mContext, batteryChangedIntent);
BatteryStatus status = verifyRefreshBatteryInfo();
assertThat(status.incompatibleCharger.get()).isFalse();
assertThat(mKeyguardUpdateMonitor.mIncompatibleCharger).isFalse();
}
private void userDeviceLockDown() {
when(mStrongAuthTracker.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(false);
when(mStrongAuthTracker.getStrongAuthForUser(mCurrentUserId))
@@ -2592,6 +2651,37 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
return intent;
}
private BatteryStatus verifyRefreshBatteryInfo() {
mTestableLooper.processAllMessages();
ArgumentCaptor<BatteryStatus> captor = ArgumentCaptor.forClass(BatteryStatus.class);
verify(mTestCallback, atLeastOnce()).onRefreshBatteryInfo(captor.capture());
List<BatteryStatus> batteryStatusList = captor.getAllValues();
return batteryStatusList.get(batteryStatusList.size() - 1);
}
private void setupIncompatibleCharging() {
final List<UsbPort> usbPorts = new ArrayList<>();
usbPorts.add(mUsbPort);
when(mUsbManager.getPorts()).thenReturn(usbPorts);
when(mUsbPort.getStatus()).thenReturn(mUsbPortStatus);
when(mUsbPort.supportsComplianceWarnings()).thenReturn(true);
when(mUsbPortStatus.isConnected()).thenReturn(true);
when(mUsbPortStatus.getComplianceWarnings()).thenReturn(new int[]{1});
}
private Context getSpyContext() {
Context contextSpy = spy(mContext);
when(contextSpy.getSystemService(UsbManager.class)).thenReturn(mUsbManager);
when(contextSpy.registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED)))
.thenReturn(new Intent(Intent.ACTION_BATTERY_CHANGED));
return contextSpy;
}
private Intent getBatteryIntent() {
return new Intent(Intent.ACTION_BATTERY_CHANGED).putExtra(
BatteryManager.EXTRA_HEALTH, BatteryManager.BATTERY_HEALTH_OVERHEAT);
}
private class TestableKeyguardUpdateMonitor extends KeyguardUpdateMonitor {
AtomicBoolean mSimStateChanged = new AtomicBoolean(false);