Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 97ca1050 authored by ykhung's avatar ykhung Committed by YK Hung
Browse files

Add incompatible charging state on the lockscreen

PRD: https://docs.google.com/document/d/1QyKNpKz45mmYt0_pln4jpVgmbrvxxKPT03BKAJrbrNs/

Test: atest KeyguardIndicationControllerTest KeyguardUpdateMonitorTest
Bug: 246960554
Change-Id: Icde56177a0e38a540ed4825e91e50df3c0bdaa3f
parent 05ead5fa
Loading
Loading
Loading
Loading
+30 −6
Original line number Diff line number Diff line
@@ -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;
    }
}
+3 −0
Original line number Diff line number Diff line
@@ -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>

+24 −6
Original line number Diff line number Diff line
@@ -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;
        }

+6 −0
Original line number Diff line number Diff line
@@ -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;
+94 −4
Original line number Diff line number Diff line
@@ -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);