Merge "Refactor FingerprintEnrollFinish to fragment"
diff --git a/src/com/android/settings/fuelgauge/BatteryBroadcastReceiver.java b/src/com/android/settings/fuelgauge/BatteryBroadcastReceiver.java
index 5e432cf..ecc4ea0 100644
--- a/src/com/android/settings/fuelgauge/BatteryBroadcastReceiver.java
+++ b/src/com/android/settings/fuelgauge/BatteryBroadcastReceiver.java
@@ -20,6 +20,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.hardware.usb.UsbManager;
 import android.os.BatteryManager;
 import android.os.PowerManager;
 import android.util.Log;
@@ -99,6 +100,7 @@
         intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED);
         intentFilter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED);
         intentFilter.addAction(BatteryUtils.BYPASS_DOCK_DEFENDER_ACTION);
+        intentFilter.addAction(UsbManager.ACTION_USB_PORT_COMPLIANCE_CHANGED);
 
         final Intent intent = mContext.registerReceiver(this, intentFilter,
                 Context.RECEIVER_EXPORTED);
@@ -110,33 +112,36 @@
     }
 
     private void updateBatteryStatus(Intent intent, boolean forceUpdate) {
-        if (intent != null && mBatteryListener != null) {
-            if (Intent.ACTION_BATTERY_CHANGED.equals(intent.getAction())) {
-                final String batteryLevel = Utils.getBatteryPercentage(intent);
-                final String batteryStatus =
-                        Utils.getBatteryStatus(mContext, intent, /* compactStatus= */ false);
-                final int batteryHealth = intent.getIntExtra(
-                        BatteryManager.EXTRA_HEALTH, BatteryManager.BATTERY_HEALTH_UNKNOWN);
-                if (!Utils.isBatteryPresent(intent)) {
-                    Log.w(TAG, "Problem reading the battery meter.");
-                    mBatteryListener.onBatteryChanged(BatteryUpdateType.BATTERY_NOT_PRESENT);
-                } else if (forceUpdate) {
-                    mBatteryListener.onBatteryChanged(BatteryUpdateType.MANUAL);
-                } else if (batteryHealth != mBatteryHealth) {
-                    mBatteryListener.onBatteryChanged(BatteryUpdateType.BATTERY_HEALTH);
-                } else if(!batteryLevel.equals(mBatteryLevel)) {
-                    mBatteryListener.onBatteryChanged(BatteryUpdateType.BATTERY_LEVEL);
-                } else if (!batteryStatus.equals(mBatteryStatus)) {
-                    mBatteryListener.onBatteryChanged(BatteryUpdateType.BATTERY_STATUS);
-                }
-                mBatteryLevel = batteryLevel;
-                mBatteryStatus = batteryStatus;
-                mBatteryHealth = batteryHealth;
-            } else if (PowerManager.ACTION_POWER_SAVE_MODE_CHANGED.equals(intent.getAction())) {
-                mBatteryListener.onBatteryChanged(BatteryUpdateType.BATTERY_SAVER);
-            } else if (BatteryUtils.BYPASS_DOCK_DEFENDER_ACTION.equals(intent.getAction())) {
+        if (intent == null || mBatteryListener == null) {
+            return;
+        }
+        final String action = intent.getAction();
+        if (Intent.ACTION_BATTERY_CHANGED.equals(action)) {
+            final String batteryLevel = Utils.getBatteryPercentage(intent);
+            final String batteryStatus =
+                    Utils.getBatteryStatus(mContext, intent, /* compactStatus= */ false);
+            final int batteryHealth = intent.getIntExtra(
+                    BatteryManager.EXTRA_HEALTH, BatteryManager.BATTERY_HEALTH_UNKNOWN);
+            if (!Utils.isBatteryPresent(intent)) {
+                Log.w(TAG, "Problem reading the battery meter.");
+                mBatteryListener.onBatteryChanged(BatteryUpdateType.BATTERY_NOT_PRESENT);
+            } else if (forceUpdate) {
+                mBatteryListener.onBatteryChanged(BatteryUpdateType.MANUAL);
+            } else if (batteryHealth != mBatteryHealth) {
+                mBatteryListener.onBatteryChanged(BatteryUpdateType.BATTERY_HEALTH);
+            } else if(!batteryLevel.equals(mBatteryLevel)) {
+                mBatteryListener.onBatteryChanged(BatteryUpdateType.BATTERY_LEVEL);
+            } else if (!batteryStatus.equals(mBatteryStatus)) {
                 mBatteryListener.onBatteryChanged(BatteryUpdateType.BATTERY_STATUS);
             }
+            mBatteryLevel = batteryLevel;
+            mBatteryStatus = batteryStatus;
+            mBatteryHealth = batteryHealth;
+        } else if (PowerManager.ACTION_POWER_SAVE_MODE_CHANGED.equals(action)) {
+            mBatteryListener.onBatteryChanged(BatteryUpdateType.BATTERY_SAVER);
+        } else if (BatteryUtils.BYPASS_DOCK_DEFENDER_ACTION.equals(action)
+                || UsbManager.ACTION_USB_PORT_COMPLIANCE_CHANGED.equals(action)) {
+            mBatteryListener.onBatteryChanged(BatteryUpdateType.BATTERY_STATUS);
         }
     }
 }
diff --git a/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoader.java b/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoader.java
index da646cb..437ffda 100644
--- a/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoader.java
+++ b/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoader.java
@@ -26,6 +26,7 @@
 import com.android.settings.fuelgauge.batterytip.detectors.BatteryDefenderDetector;
 import com.android.settings.fuelgauge.batterytip.detectors.DockDefenderDetector;
 import com.android.settings.fuelgauge.batterytip.detectors.HighUsageDetector;
+import com.android.settings.fuelgauge.batterytip.detectors.IncompatibleChargerDetector;
 import com.android.settings.fuelgauge.batterytip.detectors.LowBatteryDetector;
 import com.android.settings.fuelgauge.batterytip.detectors.SmartBatteryDetector;
 import com.android.settings.fuelgauge.batterytip.tips.BatteryTip;
@@ -59,15 +60,15 @@
         final List<BatteryTip> tips = new ArrayList<>();
         final BatteryTipPolicy policy = new BatteryTipPolicy(getContext());
         final BatteryInfo batteryInfo = mBatteryUtils.getBatteryInfo(TAG);
-        final Context context = getContext();
+        final Context context = getContext().getApplicationContext();
 
         tips.add(new LowBatteryDetector(context, policy, batteryInfo).detect());
         tips.add(new HighUsageDetector(context, policy, mBatteryUsageStats, batteryInfo).detect());
         tips.add(new SmartBatteryDetector(
                 context, policy, batteryInfo, context.getContentResolver()).detect());
-        tips.add(new BatteryDefenderDetector(
-                batteryInfo, context.getApplicationContext()).detect());
-        tips.add(new DockDefenderDetector(batteryInfo, context.getApplicationContext()).detect());
+        tips.add(new BatteryDefenderDetector(batteryInfo, context).detect());
+        tips.add(new DockDefenderDetector(batteryInfo, context).detect());
+        tips.add(new IncompatibleChargerDetector(context, batteryInfo).detect());
         Collections.sort(tips);
         return tips;
     }
diff --git a/src/com/android/settings/fuelgauge/batterytip/detectors/IncompatibleChargerDetector.java b/src/com/android/settings/fuelgauge/batterytip/detectors/IncompatibleChargerDetector.java
new file mode 100644
index 0000000..483e37d
--- /dev/null
+++ b/src/com/android/settings/fuelgauge/batterytip/detectors/IncompatibleChargerDetector.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.settings.fuelgauge.batterytip.detectors;
+
+import android.content.Context;
+import android.util.Log;
+
+import com.android.settings.fuelgauge.BatteryInfo;
+import com.android.settings.fuelgauge.batterytip.tips.BatteryTip;
+import com.android.settings.fuelgauge.batterytip.tips.IncompatibleChargerTip;
+import com.android.settingslib.Utils;
+
+/** Detect whether it is in the incompatible charging state */
+public final class IncompatibleChargerDetector implements BatteryTipDetector {
+    private static final String TAG = "IncompatibleChargerDetector";
+
+    private final Context mContext;
+    private final BatteryInfo mBatteryInfo;
+
+    public IncompatibleChargerDetector(Context context, BatteryInfo batteryInfo) {
+        mContext = context;
+        mBatteryInfo = batteryInfo;
+    }
+
+    @Override
+    public BatteryTip detect() {
+        int state = BatteryTip.StateType.INVISIBLE;
+        boolean isIncompatibleCharging = false;
+
+        // Check incompatible charging state if the device is plugged.
+        if (mBatteryInfo.pluggedStatus != 0) {
+            isIncompatibleCharging = Utils.containsIncompatibleChargers(mContext, TAG);
+            if (isIncompatibleCharging) {
+                state = BatteryTip.StateType.NEW;
+            }
+        }
+        Log.d(TAG, "detect() state= " + state + " isIncompatibleCharging: "
+                + isIncompatibleCharging);
+        return new IncompatibleChargerTip(state);
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryBroadcastReceiverTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryBroadcastReceiverTest.java
index 4bfb15b..a829c40 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryBroadcastReceiverTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryBroadcastReceiverTest.java
@@ -21,6 +21,7 @@
 
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
@@ -29,6 +30,8 @@
 
 import android.content.Context;
 import android.content.Intent;
+import android.content.IntentFilter;
+import android.hardware.usb.UsbManager;
 import android.os.BatteryManager;
 import android.os.PowerManager;
 
@@ -37,6 +40,7 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
@@ -55,7 +59,6 @@
     private BatteryBroadcastReceiver mBatteryBroadcastReceiver;
     private Context mContext;
     private Intent mChargingIntent;
-    private Intent mDockDefenderBypassIntent;
 
     @Before
     public void setUp() {
@@ -73,12 +76,10 @@
         mChargingIntent.putExtra(BatteryManager.EXTRA_SCALE, BATTERY_INTENT_SCALE);
         mChargingIntent
                 .putExtra(BatteryManager.EXTRA_STATUS, BatteryManager.BATTERY_STATUS_CHARGING);
-        mDockDefenderBypassIntent = new Intent(BatteryUtils.BYPASS_DOCK_DEFENDER_ACTION);
-
     }
 
     @Test
-    public void testOnReceive_batteryLevelChanged_dataUpdated() {
+    public void onReceive_batteryLevelChanged_dataUpdated() {
         mBatteryBroadcastReceiver.onReceive(mContext, mChargingIntent);
 
         assertThat(mBatteryBroadcastReceiver.mBatteryLevel)
@@ -89,7 +90,7 @@
     }
 
     @Test
-    public void testOnReceive_batteryHealthChanged_dataUpdated() {
+    public void onReceive_batteryHealthChanged_dataUpdated() {
         mChargingIntent
                 .putExtra(BatteryManager.EXTRA_HEALTH, BatteryManager.BATTERY_HEALTH_OVERHEAT);
         mBatteryBroadcastReceiver.onReceive(mContext, mChargingIntent);
@@ -109,7 +110,7 @@
     }
 
     @Test
-    public void testOnReceive_powerSaveModeChanged_listenerInvoked() {
+    public void onReceive_powerSaveModeChanged_listenerInvoked() {
         mBatteryBroadcastReceiver.onReceive(mContext,
                 new Intent(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED));
 
@@ -117,7 +118,7 @@
     }
 
     @Test
-    public void testOnReceive_batteryDataNotChanged_listenerNotInvoked() {
+    public void onReceive_batteryDataNotChanged_listenerNotInvoked() {
         final String batteryLevel = Utils.getBatteryPercentage(mChargingIntent);
         final String batteryStatus =
                 Utils.getBatteryStatus(mContext, mChargingIntent, /* compactStatus= */ false);
@@ -134,14 +135,23 @@
     }
 
     @Test
-    public void testOnReceive_dockDefenderBypassed_listenerInvoked() {
-        mBatteryBroadcastReceiver.onReceive(mContext, mDockDefenderBypassIntent);
+    public void onReceive_dockDefenderBypassed_listenerInvoked() {
+        mBatteryBroadcastReceiver.onReceive(mContext,
+                new Intent(BatteryUtils.BYPASS_DOCK_DEFENDER_ACTION));
 
         verify(mBatteryListener).onBatteryChanged(BatteryUpdateType.BATTERY_STATUS);
     }
 
     @Test
-    public void testRegister_updateBatteryStatus() {
+    public void onReceive_usbPortComplianceChanged_listenerInvoked() {
+        mBatteryBroadcastReceiver.onReceive(mContext,
+                new Intent(UsbManager.ACTION_USB_PORT_COMPLIANCE_CHANGED));
+
+        verify(mBatteryListener).onBatteryChanged(BatteryUpdateType.BATTERY_STATUS);
+    }
+
+    @Test
+    public void register_updateBatteryStatus() {
         doReturn(mChargingIntent).when(mContext).registerReceiver(any(), any(), anyInt());
 
         mBatteryBroadcastReceiver.register();
@@ -156,4 +166,23 @@
         // 2 times because register will force update the battery
         verify(mBatteryListener, times(2)).onBatteryChanged(BatteryUpdateType.MANUAL);
     }
+
+    @Test
+    public void register_registerExpectedIntent() {
+        mBatteryBroadcastReceiver.register();
+
+        ArgumentCaptor<IntentFilter> captor = ArgumentCaptor.forClass(IntentFilter.class);
+        verify(mContext).registerReceiver(
+                eq(mBatteryBroadcastReceiver),
+                captor.capture(),
+                eq(Context.RECEIVER_EXPORTED));
+        assertAction(captor, Intent.ACTION_BATTERY_CHANGED);
+        assertAction(captor, PowerManager.ACTION_POWER_SAVE_MODE_CHANGED);
+        assertAction(captor, BatteryUtils.BYPASS_DOCK_DEFENDER_ACTION);
+        assertAction(captor, UsbManager.ACTION_USB_PORT_COMPLIANCE_CHANGED);
+    }
+
+    private void assertAction(ArgumentCaptor<IntentFilter> captor, String action) {
+        assertThat(captor.getValue().hasAction(action)).isTrue();
+    }
 }
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoaderTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoaderTest.java
index 0e1c458..5b0ae04 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoaderTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoaderTest.java
@@ -53,6 +53,7 @@
             BatteryTip.TipType.LOW_BATTERY,
             BatteryTip.TipType.BATTERY_DEFENDER,
             BatteryTip.TipType.DOCK_DEFENDER,
+            BatteryTip.TipType.INCOMPATIBLE_CHARGER,
             BatteryTip.TipType.HIGH_DEVICE_USAGE,
             BatteryTip.TipType.SMART_BATTERY_MANAGER};
     @Mock(answer = Answers.RETURNS_DEEP_STUBS)
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/IncompatibleChargerDetectorTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/IncompatibleChargerDetectorTest.java
new file mode 100644
index 0000000..1dfe6e2
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/IncompatibleChargerDetectorTest.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.settings.fuelgauge.batterytip.detectors;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.hardware.usb.UsbManager;
+import android.hardware.usb.UsbPort;
+import android.hardware.usb.UsbPortStatus;
+
+import com.android.settings.fuelgauge.BatteryInfo;
+import com.android.settings.fuelgauge.batterytip.tips.BatteryTip;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@RunWith(RobolectricTestRunner.class)
+public final class IncompatibleChargerDetectorTest {
+
+    @Mock private BatteryInfo mBatteryInfo;
+    @Mock private UsbPort mUsbPort;
+    @Mock private UsbManager mUsbManager;
+    @Mock private UsbPortStatus mUsbPortStatus;
+
+    private Context mContext;
+    private IncompatibleChargerDetector mIncompatibleChargerDetector;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mContext = spy(RuntimeEnvironment.application);
+        when(mContext.getSystemService(UsbManager.class)).thenReturn(mUsbManager);
+        mIncompatibleChargerDetector =
+                new IncompatibleChargerDetector(mContext, mBatteryInfo);
+    }
+
+    @Test
+    public void detect_unplugDevice_shouldNotShowTip() {
+        mBatteryInfo.pluggedStatus = 0;
+
+        BatteryTip batteryTip = mIncompatibleChargerDetector.detect();
+
+        assertThat(batteryTip.isVisible()).isFalse();
+        assertThat(batteryTip.getState()).isEqualTo(BatteryTip.StateType.INVISIBLE);
+    }
+
+    @Test
+    public void detect_plugDeviceWithoutIncompatibleCharger_shouldNotShowTip() {
+        mBatteryInfo.pluggedStatus = 1;
+
+        BatteryTip batteryTip = mIncompatibleChargerDetector.detect();
+
+        assertThat(batteryTip.isVisible()).isFalse();
+        assertThat(batteryTip.getState()).isEqualTo(BatteryTip.StateType.INVISIBLE);
+    }
+
+    @Test
+    public void detect_plugDeviceWithIncompatibleCharger_showTip() {
+        mBatteryInfo.pluggedStatus = 1;
+        setupIncompatibleCharging();
+
+        BatteryTip batteryTip = mIncompatibleChargerDetector.detect();
+
+        assertThat(batteryTip.isVisible()).isTrue();
+        assertThat(batteryTip.getState()).isEqualTo(BatteryTip.StateType.NEW);
+    }
+
+    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});
+    }
+}