Loading packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatteryStatus.java +30 −6 Original line number Original line Diff line number Diff line Loading @@ -34,6 +34,8 @@ import android.os.BatteryManager; import com.android.settingslib.R; import com.android.settingslib.R; import java.util.Optional; /** /** * Stores and computes some battery information. * Stores and computes some battery information. */ */ Loading @@ -52,11 +54,12 @@ public class BatteryStatus { public final int health; public final int health; public final int maxChargingWattage; public final int maxChargingWattage; public final boolean present; 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); final Intent batteryChangedIntent = BatteryUtils.getBatteryIntent(context); return batteryChangedIntent == null return batteryChangedIntent == null ? null : new BatteryStatus(batteryChangedIntent); ? null : new BatteryStatus(batteryChangedIntent, incompatibleCharger); } } public BatteryStatus(int status, int level, int plugged, int health, public BatteryStatus(int status, int level, int plugged, int health, Loading @@ -67,14 +70,25 @@ public class BatteryStatus { this.health = health; this.health = health; this.maxChargingWattage = maxChargingWattage; this.maxChargingWattage = maxChargingWattage; this.present = present; this.present = present; this.incompatibleCharger = Optional.empty(); } } public BatteryStatus(Intent batteryChangedIntent) { 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); status = batteryChangedIntent.getIntExtra(EXTRA_STATUS, BATTERY_STATUS_UNKNOWN); plugged = batteryChangedIntent.getIntExtra(EXTRA_PLUGGED, 0); plugged = batteryChangedIntent.getIntExtra(EXTRA_PLUGGED, 0); level = getBatteryLevel(batteryChangedIntent); level = getBatteryLevel(batteryChangedIntent); health = batteryChangedIntent.getIntExtra(EXTRA_HEALTH, BATTERY_HEALTH_UNKNOWN); health = batteryChangedIntent.getIntExtra(EXTRA_HEALTH, BATTERY_HEALTH_UNKNOWN); present = batteryChangedIntent.getBooleanExtra(EXTRA_PRESENT, true); present = batteryChangedIntent.getBooleanExtra(EXTRA_PRESENT, true); this.incompatibleCharger = incompatibleCharger; final int maxChargingMicroAmp = batteryChangedIntent.getIntExtra(EXTRA_MAX_CHARGING_CURRENT, final int maxChargingMicroAmp = batteryChangedIntent.getIntExtra(EXTRA_MAX_CHARGING_CURRENT, -1); -1); Loading @@ -95,10 +109,7 @@ public class BatteryStatus { /** Determine whether the device is plugged. */ /** Determine whether the device is plugged. */ public boolean isPluggedIn() { public boolean isPluggedIn() { return plugged == BatteryManager.BATTERY_PLUGGED_AC return isPluggedIn(plugged); || plugged == BatteryManager.BATTERY_PLUGGED_USB || plugged == BatteryManager.BATTERY_PLUGGED_WIRELESS || plugged == BatteryManager.BATTERY_PLUGGED_DOCK; } } /** Determine whether the device is plugged in (USB, power). */ /** Determine whether the device is plugged in (USB, power). */ Loading Loading @@ -190,4 +201,17 @@ public class BatteryStatus { ? -1 /*invalid battery level*/ ? -1 /*invalid battery level*/ : Math.round((level / (float) scale) * 100f); : 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; } } } packages/SystemUI/res-keyguard/values/strings.xml +3 −0 Original line number Original line Diff line number Diff line Loading @@ -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. --> <!-- 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> <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. --> <!-- 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> <string name="keyguard_instructions_when_pattern_disabled">Press Menu to unlock.</string> Loading packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java +24 −6 Original line number Original line Diff line number Diff line Loading @@ -102,6 +102,7 @@ import android.hardware.fingerprint.FingerprintManager; import android.hardware.fingerprint.FingerprintManager.AuthenticationCallback; import android.hardware.fingerprint.FingerprintManager.AuthenticationCallback; import android.hardware.fingerprint.FingerprintManager.AuthenticationResult; import android.hardware.fingerprint.FingerprintManager.AuthenticationResult; import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; import android.hardware.usb.UsbManager; import android.nfc.NfcAdapter; import android.nfc.NfcAdapter; import android.os.CancellationSignal; import android.os.CancellationSignal; import android.os.Handler; import android.os.Handler; Loading Loading @@ -138,6 +139,7 @@ import com.android.internal.widget.LockPatternUtils; import com.android.keyguard.logging.KeyguardUpdateMonitorLogger; import com.android.keyguard.logging.KeyguardUpdateMonitorLogger; import com.android.settingslib.WirelessUtils; import com.android.settingslib.WirelessUtils; import com.android.settingslib.fuelgauge.BatteryStatus; import com.android.settingslib.fuelgauge.BatteryStatus; import com.android.settingslib.Utils; import com.android.systemui.Dumpable; import com.android.systemui.Dumpable; import com.android.systemui.R; import com.android.systemui.R; import com.android.systemui.biometrics.AuthController; import com.android.systemui.biometrics.AuthController; Loading Loading @@ -329,6 +331,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab // Battery status // Battery status @VisibleForTesting @VisibleForTesting BatteryStatus mBatteryStatus; BatteryStatus mBatteryStatus; @VisibleForTesting boolean mIncompatibleCharger; private StrongAuthTracker mStrongAuthTracker; private StrongAuthTracker mStrongAuthTracker; Loading Loading @@ -1572,10 +1576,20 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab MSG_TIMEZONE_UPDATE, intent.getStringExtra(Intent.EXTRA_TIMEZONE)); MSG_TIMEZONE_UPDATE, intent.getStringExtra(Intent.EXTRA_TIMEZONE)); mHandler.sendMessage(msg); mHandler.sendMessage(msg); } else if (Intent.ACTION_BATTERY_CHANGED.equals(action)) { } 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( final Message msg = mHandler.obtainMessage( MSG_BATTERY_UPDATE, new BatteryStatus(intent)); MSG_BATTERY_UPDATE, new BatteryStatus(intent, mIncompatibleCharger)); mHandler.sendMessage(msg); 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)) { } else if (Intent.ACTION_SIM_STATE_CHANGED.equals(action)) { SimData args = SimData.fromIntent(intent); SimData args = SimData.fromIntent(intent); // ACTION_SIM_STATE_CHANGED is rebroadcast after unlocking the device to // ACTION_SIM_STATE_CHANGED is rebroadcast after unlocking the device to Loading Loading @@ -2251,6 +2265,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab filter.addAction(TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED); filter.addAction(TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED); filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED); filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED); filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED); filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED); filter.addAction(UsbManager.ACTION_USB_PORT_COMPLIANCE_CHANGED); mBroadcastDispatcher.registerReceiverWithHandler(mBroadcastReceiver, filter, mHandler); mBroadcastDispatcher.registerReceiverWithHandler(mBroadcastReceiver, filter, mHandler); // Since ACTION_SERVICE_STATE is being moved to a non-sticky broadcast, trigger the // Since ACTION_SERVICE_STATE is being moved to a non-sticky broadcast, trigger the // listener now with the service state from the default sub. // listener now with the service state from the default sub. Loading Loading @@ -3527,8 +3542,6 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab final boolean wasPluggedIn = old.isPluggedIn(); final boolean wasPluggedIn = old.isPluggedIn(); final boolean stateChangedWhilePluggedIn = wasPluggedIn && nowPluggedIn final boolean stateChangedWhilePluggedIn = wasPluggedIn && nowPluggedIn && (old.status != current.status); && (old.status != current.status); final boolean nowPresent = current.present; final boolean wasPresent = old.present; // change in plug state is always interesting // change in plug state is always interesting if (wasPluggedIn != nowPluggedIn || stateChangedWhilePluggedIn) { if (wasPluggedIn != nowPluggedIn || stateChangedWhilePluggedIn) { Loading @@ -3545,8 +3558,13 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab return true; return true; } } // Battery either showed up or disappeared // change in battery is present or not if (wasPresent != nowPresent) { if (old.present != current.present) { return true; } // change in the incompatible charger if (!old.incompatibleCharger.equals(current.incompatibleCharger)) { return true; return true; } } Loading packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java +6 −0 Original line number Original line Diff line number Diff line Loading @@ -185,6 +185,7 @@ public class KeyguardIndicationController { private boolean mPowerCharged; private boolean mPowerCharged; private boolean mBatteryOverheated; private boolean mBatteryOverheated; private boolean mEnableBatteryDefender; private boolean mEnableBatteryDefender; private boolean mIncompatibleCharger; private int mChargingSpeed; private int mChargingSpeed; private int mChargingWattage; private int mChargingWattage; private int mBatteryLevel; private int mBatteryLevel; Loading Loading @@ -903,6 +904,10 @@ public class KeyguardIndicationController { chargingId = R.string.keyguard_plugged_in_charging_limited; chargingId = R.string.keyguard_plugged_in_charging_limited; String percentage = NumberFormat.getPercentInstance().format(mBatteryLevel / 100f); String percentage = NumberFormat.getPercentInstance().format(mBatteryLevel / 100f); return mContext.getResources().getString(chargingId, percentage); 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) { } else if (mPowerCharged) { return mContext.getResources().getString(R.string.keyguard_charged); return mContext.getResources().getString(R.string.keyguard_charged); } } Loading Loading @@ -1063,6 +1068,7 @@ public class KeyguardIndicationController { mBatteryPresent = status.present; mBatteryPresent = status.present; mBatteryOverheated = status.isOverheated(); mBatteryOverheated = status.isOverheated(); mEnableBatteryDefender = mBatteryOverheated && status.isPluggedIn(); mEnableBatteryDefender = mBatteryOverheated && status.isPluggedIn(); mIncompatibleCharger = status.incompatibleCharger.orElse(false); try { try { mChargingTimeRemaining = mPowerPluggedIn mChargingTimeRemaining = mPowerPluggedIn ? mBatteryInfo.computeChargeTimeRemaining() : -1; ? mBatteryInfo.computeChargeTimeRemaining() : -1; Loading packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java +94 −4 Original line number Original line Diff line number Diff line Loading @@ -85,8 +85,12 @@ import android.hardware.face.FaceSensorPropertiesInternal; import android.hardware.fingerprint.FingerprintManager; import android.hardware.fingerprint.FingerprintManager; import android.hardware.fingerprint.FingerprintSensorProperties; import android.hardware.fingerprint.FingerprintSensorProperties; import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; 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.net.Uri; import android.nfc.NfcAdapter; import android.nfc.NfcAdapter; import android.os.BatteryManager; import android.os.Bundle; import android.os.Bundle; import android.os.CancellationSignal; import android.os.CancellationSignal; import android.os.Handler; import android.os.Handler; Loading Loading @@ -117,6 +121,7 @@ import com.android.internal.widget.ILockSettings; import com.android.internal.widget.LockPatternUtils; import com.android.internal.widget.LockPatternUtils; import com.android.keyguard.KeyguardUpdateMonitor.BiometricAuthenticated; import com.android.keyguard.KeyguardUpdateMonitor.BiometricAuthenticated; import com.android.keyguard.logging.KeyguardUpdateMonitorLogger; import com.android.keyguard.logging.KeyguardUpdateMonitorLogger; import com.android.settingslib.fuelgauge.BatteryStatus; import com.android.systemui.SysuiTestCase; import com.android.systemui.SysuiTestCase; import com.android.systemui.biometrics.AuthController; import com.android.systemui.biometrics.AuthController; import com.android.systemui.biometrics.FingerprintInteractiveToAuthProvider; import com.android.systemui.biometrics.FingerprintInteractiveToAuthProvider; Loading Loading @@ -238,9 +243,16 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { private UiEventLogger mUiEventLogger; private UiEventLogger mUiEventLogger; @Mock @Mock private GlobalSettings mGlobalSettings; private GlobalSettings mGlobalSettings; private FaceWakeUpTriggersConfig mFaceWakeUpTriggersConfig; @Mock @Mock private FingerprintInteractiveToAuthProvider mInteractiveToAuthProvider; private FingerprintInteractiveToAuthProvider mInteractiveToAuthProvider; @Mock private UsbPort mUsbPort; @Mock private UsbManager mUsbManager; @Mock private UsbPortStatus mUsbPortStatus; @Mock private Uri mURI; private List<FingerprintSensorPropertiesInternal> mFingerprintSensorProperties; private List<FingerprintSensorPropertiesInternal> mFingerprintSensorProperties; private final int mCurrentUserId = 100; private final int mCurrentUserId = 100; Loading @@ -252,9 +264,6 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { @Captor @Captor private ArgumentCaptor<FaceManager.AuthenticationCallback> mAuthenticationCallbackCaptor; private ArgumentCaptor<FaceManager.AuthenticationCallback> mAuthenticationCallbackCaptor; @Mock private Uri mURI; // Direct executor // Direct executor private final Executor mBackgroundExecutor = Runnable::run; private final Executor mBackgroundExecutor = Runnable::run; private final Executor mMainExecutor = Runnable::run; private final Executor mMainExecutor = Runnable::run; Loading @@ -264,6 +273,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { private MockitoSession mMockitoSession; private MockitoSession mMockitoSession; private StatusBarStateController.StateListener mStatusBarStateListener; private StatusBarStateController.StateListener mStatusBarStateListener; private IBiometricEnabledOnKeyguardCallback mBiometricEnabledOnKeyguardCallback; private IBiometricEnabledOnKeyguardCallback mBiometricEnabledOnKeyguardCallback; private FaceWakeUpTriggersConfig mFaceWakeUpTriggersConfig; private final InstanceId mKeyguardInstanceId = InstanceId.fakeInstanceId(999); private final InstanceId mKeyguardInstanceId = InstanceId.fakeInstanceId(999); @Before @Before Loading Loading @@ -2373,6 +2383,55 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { assertThat(mKeyguardUpdateMonitor.shouldListenForFace()).isTrue(); 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() { private void userDeviceLockDown() { when(mStrongAuthTracker.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(false); when(mStrongAuthTracker.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(false); when(mStrongAuthTracker.getStrongAuthForUser(mCurrentUserId)) when(mStrongAuthTracker.getStrongAuthForUser(mCurrentUserId)) Loading Loading @@ -2592,6 +2651,37 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { return intent; 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 { private class TestableKeyguardUpdateMonitor extends KeyguardUpdateMonitor { AtomicBoolean mSimStateChanged = new AtomicBoolean(false); AtomicBoolean mSimStateChanged = new AtomicBoolean(false); Loading Loading
packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatteryStatus.java +30 −6 Original line number Original line Diff line number Diff line Loading @@ -34,6 +34,8 @@ import android.os.BatteryManager; import com.android.settingslib.R; import com.android.settingslib.R; import java.util.Optional; /** /** * Stores and computes some battery information. * Stores and computes some battery information. */ */ Loading @@ -52,11 +54,12 @@ public class BatteryStatus { public final int health; public final int health; public final int maxChargingWattage; public final int maxChargingWattage; public final boolean present; 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); final Intent batteryChangedIntent = BatteryUtils.getBatteryIntent(context); return batteryChangedIntent == null return batteryChangedIntent == null ? null : new BatteryStatus(batteryChangedIntent); ? null : new BatteryStatus(batteryChangedIntent, incompatibleCharger); } } public BatteryStatus(int status, int level, int plugged, int health, public BatteryStatus(int status, int level, int plugged, int health, Loading @@ -67,14 +70,25 @@ public class BatteryStatus { this.health = health; this.health = health; this.maxChargingWattage = maxChargingWattage; this.maxChargingWattage = maxChargingWattage; this.present = present; this.present = present; this.incompatibleCharger = Optional.empty(); } } public BatteryStatus(Intent batteryChangedIntent) { 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); status = batteryChangedIntent.getIntExtra(EXTRA_STATUS, BATTERY_STATUS_UNKNOWN); plugged = batteryChangedIntent.getIntExtra(EXTRA_PLUGGED, 0); plugged = batteryChangedIntent.getIntExtra(EXTRA_PLUGGED, 0); level = getBatteryLevel(batteryChangedIntent); level = getBatteryLevel(batteryChangedIntent); health = batteryChangedIntent.getIntExtra(EXTRA_HEALTH, BATTERY_HEALTH_UNKNOWN); health = batteryChangedIntent.getIntExtra(EXTRA_HEALTH, BATTERY_HEALTH_UNKNOWN); present = batteryChangedIntent.getBooleanExtra(EXTRA_PRESENT, true); present = batteryChangedIntent.getBooleanExtra(EXTRA_PRESENT, true); this.incompatibleCharger = incompatibleCharger; final int maxChargingMicroAmp = batteryChangedIntent.getIntExtra(EXTRA_MAX_CHARGING_CURRENT, final int maxChargingMicroAmp = batteryChangedIntent.getIntExtra(EXTRA_MAX_CHARGING_CURRENT, -1); -1); Loading @@ -95,10 +109,7 @@ public class BatteryStatus { /** Determine whether the device is plugged. */ /** Determine whether the device is plugged. */ public boolean isPluggedIn() { public boolean isPluggedIn() { return plugged == BatteryManager.BATTERY_PLUGGED_AC return isPluggedIn(plugged); || plugged == BatteryManager.BATTERY_PLUGGED_USB || plugged == BatteryManager.BATTERY_PLUGGED_WIRELESS || plugged == BatteryManager.BATTERY_PLUGGED_DOCK; } } /** Determine whether the device is plugged in (USB, power). */ /** Determine whether the device is plugged in (USB, power). */ Loading Loading @@ -190,4 +201,17 @@ public class BatteryStatus { ? -1 /*invalid battery level*/ ? -1 /*invalid battery level*/ : Math.round((level / (float) scale) * 100f); : 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; } } }
packages/SystemUI/res-keyguard/values/strings.xml +3 −0 Original line number Original line Diff line number Diff line Loading @@ -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. --> <!-- 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> <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. --> <!-- 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> <string name="keyguard_instructions_when_pattern_disabled">Press Menu to unlock.</string> Loading
packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java +24 −6 Original line number Original line Diff line number Diff line Loading @@ -102,6 +102,7 @@ import android.hardware.fingerprint.FingerprintManager; import android.hardware.fingerprint.FingerprintManager.AuthenticationCallback; import android.hardware.fingerprint.FingerprintManager.AuthenticationCallback; import android.hardware.fingerprint.FingerprintManager.AuthenticationResult; import android.hardware.fingerprint.FingerprintManager.AuthenticationResult; import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; import android.hardware.usb.UsbManager; import android.nfc.NfcAdapter; import android.nfc.NfcAdapter; import android.os.CancellationSignal; import android.os.CancellationSignal; import android.os.Handler; import android.os.Handler; Loading Loading @@ -138,6 +139,7 @@ import com.android.internal.widget.LockPatternUtils; import com.android.keyguard.logging.KeyguardUpdateMonitorLogger; import com.android.keyguard.logging.KeyguardUpdateMonitorLogger; import com.android.settingslib.WirelessUtils; import com.android.settingslib.WirelessUtils; import com.android.settingslib.fuelgauge.BatteryStatus; import com.android.settingslib.fuelgauge.BatteryStatus; import com.android.settingslib.Utils; import com.android.systemui.Dumpable; import com.android.systemui.Dumpable; import com.android.systemui.R; import com.android.systemui.R; import com.android.systemui.biometrics.AuthController; import com.android.systemui.biometrics.AuthController; Loading Loading @@ -329,6 +331,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab // Battery status // Battery status @VisibleForTesting @VisibleForTesting BatteryStatus mBatteryStatus; BatteryStatus mBatteryStatus; @VisibleForTesting boolean mIncompatibleCharger; private StrongAuthTracker mStrongAuthTracker; private StrongAuthTracker mStrongAuthTracker; Loading Loading @@ -1572,10 +1576,20 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab MSG_TIMEZONE_UPDATE, intent.getStringExtra(Intent.EXTRA_TIMEZONE)); MSG_TIMEZONE_UPDATE, intent.getStringExtra(Intent.EXTRA_TIMEZONE)); mHandler.sendMessage(msg); mHandler.sendMessage(msg); } else if (Intent.ACTION_BATTERY_CHANGED.equals(action)) { } 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( final Message msg = mHandler.obtainMessage( MSG_BATTERY_UPDATE, new BatteryStatus(intent)); MSG_BATTERY_UPDATE, new BatteryStatus(intent, mIncompatibleCharger)); mHandler.sendMessage(msg); 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)) { } else if (Intent.ACTION_SIM_STATE_CHANGED.equals(action)) { SimData args = SimData.fromIntent(intent); SimData args = SimData.fromIntent(intent); // ACTION_SIM_STATE_CHANGED is rebroadcast after unlocking the device to // ACTION_SIM_STATE_CHANGED is rebroadcast after unlocking the device to Loading Loading @@ -2251,6 +2265,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab filter.addAction(TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED); filter.addAction(TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED); filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED); filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED); filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED); filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED); filter.addAction(UsbManager.ACTION_USB_PORT_COMPLIANCE_CHANGED); mBroadcastDispatcher.registerReceiverWithHandler(mBroadcastReceiver, filter, mHandler); mBroadcastDispatcher.registerReceiverWithHandler(mBroadcastReceiver, filter, mHandler); // Since ACTION_SERVICE_STATE is being moved to a non-sticky broadcast, trigger the // Since ACTION_SERVICE_STATE is being moved to a non-sticky broadcast, trigger the // listener now with the service state from the default sub. // listener now with the service state from the default sub. Loading Loading @@ -3527,8 +3542,6 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab final boolean wasPluggedIn = old.isPluggedIn(); final boolean wasPluggedIn = old.isPluggedIn(); final boolean stateChangedWhilePluggedIn = wasPluggedIn && nowPluggedIn final boolean stateChangedWhilePluggedIn = wasPluggedIn && nowPluggedIn && (old.status != current.status); && (old.status != current.status); final boolean nowPresent = current.present; final boolean wasPresent = old.present; // change in plug state is always interesting // change in plug state is always interesting if (wasPluggedIn != nowPluggedIn || stateChangedWhilePluggedIn) { if (wasPluggedIn != nowPluggedIn || stateChangedWhilePluggedIn) { Loading @@ -3545,8 +3558,13 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab return true; return true; } } // Battery either showed up or disappeared // change in battery is present or not if (wasPresent != nowPresent) { if (old.present != current.present) { return true; } // change in the incompatible charger if (!old.incompatibleCharger.equals(current.incompatibleCharger)) { return true; return true; } } Loading
packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java +6 −0 Original line number Original line Diff line number Diff line Loading @@ -185,6 +185,7 @@ public class KeyguardIndicationController { private boolean mPowerCharged; private boolean mPowerCharged; private boolean mBatteryOverheated; private boolean mBatteryOverheated; private boolean mEnableBatteryDefender; private boolean mEnableBatteryDefender; private boolean mIncompatibleCharger; private int mChargingSpeed; private int mChargingSpeed; private int mChargingWattage; private int mChargingWattage; private int mBatteryLevel; private int mBatteryLevel; Loading Loading @@ -903,6 +904,10 @@ public class KeyguardIndicationController { chargingId = R.string.keyguard_plugged_in_charging_limited; chargingId = R.string.keyguard_plugged_in_charging_limited; String percentage = NumberFormat.getPercentInstance().format(mBatteryLevel / 100f); String percentage = NumberFormat.getPercentInstance().format(mBatteryLevel / 100f); return mContext.getResources().getString(chargingId, percentage); 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) { } else if (mPowerCharged) { return mContext.getResources().getString(R.string.keyguard_charged); return mContext.getResources().getString(R.string.keyguard_charged); } } Loading Loading @@ -1063,6 +1068,7 @@ public class KeyguardIndicationController { mBatteryPresent = status.present; mBatteryPresent = status.present; mBatteryOverheated = status.isOverheated(); mBatteryOverheated = status.isOverheated(); mEnableBatteryDefender = mBatteryOverheated && status.isPluggedIn(); mEnableBatteryDefender = mBatteryOverheated && status.isPluggedIn(); mIncompatibleCharger = status.incompatibleCharger.orElse(false); try { try { mChargingTimeRemaining = mPowerPluggedIn mChargingTimeRemaining = mPowerPluggedIn ? mBatteryInfo.computeChargeTimeRemaining() : -1; ? mBatteryInfo.computeChargeTimeRemaining() : -1; Loading
packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java +94 −4 Original line number Original line Diff line number Diff line Loading @@ -85,8 +85,12 @@ import android.hardware.face.FaceSensorPropertiesInternal; import android.hardware.fingerprint.FingerprintManager; import android.hardware.fingerprint.FingerprintManager; import android.hardware.fingerprint.FingerprintSensorProperties; import android.hardware.fingerprint.FingerprintSensorProperties; import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; 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.net.Uri; import android.nfc.NfcAdapter; import android.nfc.NfcAdapter; import android.os.BatteryManager; import android.os.Bundle; import android.os.Bundle; import android.os.CancellationSignal; import android.os.CancellationSignal; import android.os.Handler; import android.os.Handler; Loading Loading @@ -117,6 +121,7 @@ import com.android.internal.widget.ILockSettings; import com.android.internal.widget.LockPatternUtils; import com.android.internal.widget.LockPatternUtils; import com.android.keyguard.KeyguardUpdateMonitor.BiometricAuthenticated; import com.android.keyguard.KeyguardUpdateMonitor.BiometricAuthenticated; import com.android.keyguard.logging.KeyguardUpdateMonitorLogger; import com.android.keyguard.logging.KeyguardUpdateMonitorLogger; import com.android.settingslib.fuelgauge.BatteryStatus; import com.android.systemui.SysuiTestCase; import com.android.systemui.SysuiTestCase; import com.android.systemui.biometrics.AuthController; import com.android.systemui.biometrics.AuthController; import com.android.systemui.biometrics.FingerprintInteractiveToAuthProvider; import com.android.systemui.biometrics.FingerprintInteractiveToAuthProvider; Loading Loading @@ -238,9 +243,16 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { private UiEventLogger mUiEventLogger; private UiEventLogger mUiEventLogger; @Mock @Mock private GlobalSettings mGlobalSettings; private GlobalSettings mGlobalSettings; private FaceWakeUpTriggersConfig mFaceWakeUpTriggersConfig; @Mock @Mock private FingerprintInteractiveToAuthProvider mInteractiveToAuthProvider; private FingerprintInteractiveToAuthProvider mInteractiveToAuthProvider; @Mock private UsbPort mUsbPort; @Mock private UsbManager mUsbManager; @Mock private UsbPortStatus mUsbPortStatus; @Mock private Uri mURI; private List<FingerprintSensorPropertiesInternal> mFingerprintSensorProperties; private List<FingerprintSensorPropertiesInternal> mFingerprintSensorProperties; private final int mCurrentUserId = 100; private final int mCurrentUserId = 100; Loading @@ -252,9 +264,6 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { @Captor @Captor private ArgumentCaptor<FaceManager.AuthenticationCallback> mAuthenticationCallbackCaptor; private ArgumentCaptor<FaceManager.AuthenticationCallback> mAuthenticationCallbackCaptor; @Mock private Uri mURI; // Direct executor // Direct executor private final Executor mBackgroundExecutor = Runnable::run; private final Executor mBackgroundExecutor = Runnable::run; private final Executor mMainExecutor = Runnable::run; private final Executor mMainExecutor = Runnable::run; Loading @@ -264,6 +273,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { private MockitoSession mMockitoSession; private MockitoSession mMockitoSession; private StatusBarStateController.StateListener mStatusBarStateListener; private StatusBarStateController.StateListener mStatusBarStateListener; private IBiometricEnabledOnKeyguardCallback mBiometricEnabledOnKeyguardCallback; private IBiometricEnabledOnKeyguardCallback mBiometricEnabledOnKeyguardCallback; private FaceWakeUpTriggersConfig mFaceWakeUpTriggersConfig; private final InstanceId mKeyguardInstanceId = InstanceId.fakeInstanceId(999); private final InstanceId mKeyguardInstanceId = InstanceId.fakeInstanceId(999); @Before @Before Loading Loading @@ -2373,6 +2383,55 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { assertThat(mKeyguardUpdateMonitor.shouldListenForFace()).isTrue(); 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() { private void userDeviceLockDown() { when(mStrongAuthTracker.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(false); when(mStrongAuthTracker.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(false); when(mStrongAuthTracker.getStrongAuthForUser(mCurrentUserId)) when(mStrongAuthTracker.getStrongAuthForUser(mCurrentUserId)) Loading Loading @@ -2592,6 +2651,37 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { return intent; 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 { private class TestableKeyguardUpdateMonitor extends KeyguardUpdateMonitor { AtomicBoolean mSimStateChanged = new AtomicBoolean(false); AtomicBoolean mSimStateChanged = new AtomicBoolean(false); Loading