Merge "Import translations. DO NOT MERGE ANYWHERE" into tm-qpr-dev
diff --git a/res/drawable-night/ic_battery_status_protected_24dp.xml b/res/drawable-night/ic_battery_status_protected_24dp.xml
new file mode 100644
index 0000000..23386cb
--- /dev/null
+++ b/res/drawable-night/ic_battery_status_protected_24dp.xml
@@ -0,0 +1,30 @@
+<!--
+  ~ Copyright (C) 2022 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.
+  -->
+
+<vector
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:name="vector"
+    android:width="16dp"
+    android:height="16dp"
+    android:viewportWidth="16"
+    android:viewportHeight="16">
+    <path
+        android:name="path_1"
+        android:pathData="M 11.739 14.409 C 11.572 14.576 11.346 14.67 11.11 14.67 L 4.89 14.67 C 4.654 14.67 4.428 14.576 4.261 14.409 C 4.094 14.242 4 14.016 4 13.78 L 4 3.55 C 4 3.316 4.092 3.091 4.257 2.924 C 4.422 2.758 4.646 2.663 4.88 2.66 L 6.33 2.66 L 6.33 1.33 L 9.66 1.33 L 9.66 2.66 L 11.11 2.66 C 11.227 2.66 11.343 2.683 11.451 2.728 C 11.559 2.773 11.657 2.838 11.739 2.921 C 11.822 3.003 11.887 3.102 11.932 3.209 C 11.977 3.317 12 3.433 12 3.55 L 12 13.78 C 12 14.016 11.906 14.242 11.739 14.409 Z M 6 9 L 8.67 4 L 8.67 7.67 L 10 7.67 L 7.33 12.67 L 7.33 9 L 6 9 Z"
+        android:fillColor="#ffffff"
+        android:strokeWidth="1"
+        android:fillType="evenOdd"/>
+</vector>
\ No newline at end of file
diff --git a/res/drawable/ic_battery_status_protected_24dp.xml b/res/drawable/ic_battery_status_protected_24dp.xml
new file mode 100644
index 0000000..8841710
--- /dev/null
+++ b/res/drawable/ic_battery_status_protected_24dp.xml
@@ -0,0 +1,30 @@
+<!--
+  ~ Copyright (C) 2022 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.
+  -->
+
+<vector
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:name="vector"
+    android:width="16dp"
+    android:height="16dp"
+    android:viewportWidth="16"
+    android:viewportHeight="16">
+    <path
+        android:name="path"
+        android:pathData="M 11.739 14.409 C 11.572 14.576 11.346 14.67 11.11 14.67 L 4.89 14.67 C 4.654 14.67 4.428 14.576 4.261 14.409 C 4.094 14.242 4 14.016 4 13.78 L 4 3.55 C 4 3.316 4.092 3.091 4.257 2.924 C 4.422 2.758 4.646 2.663 4.88 2.66 L 6.33 2.66 L 6.33 1.33 L 9.66 1.33 L 9.66 2.66 L 11.11 2.66 C 11.227 2.66 11.343 2.683 11.451 2.728 C 11.559 2.773 11.657 2.838 11.739 2.921 C 11.822 3.003 11.887 3.102 11.932 3.209 C 11.977 3.317 12 3.433 12 3.55 L 12 13.78 C 12 14.016 11.906 14.242 11.739 14.409 Z M 6 9 L 8.67 4 L 8.67 7.67 L 10 7.67 L 7.33 12.67 L 7.33 9 L 6 9 Z"
+        android:fillColor="#000000"
+        android:strokeWidth="1"
+        android:fillType="evenOdd"/>
+</vector>
\ No newline at end of file
diff --git a/res/values-am/arrays.xml b/res/values-am/arrays.xml
index 0650db6..626ce41 100644
--- a/res/values-am/arrays.xml
+++ b/res/values-am/arrays.xml
@@ -586,7 +586,9 @@
     <item msgid="2373999996715432397">"0"</item>
     <item msgid="5305176997036663262">"1"</item>
   </string-array>
-    <!-- no translation found for switch_to_dock_user_when_docked_timeout_entries:0 (3211660022507486536) -->
-    <!-- no translation found for switch_to_dock_user_when_docked_timeout_entries:1 (7025253383416830453) -->
-    <!-- no translation found for switch_to_dock_user_when_docked_timeout_entries:2 (1574040255478150028) -->
+  <string-array name="switch_to_dock_user_when_docked_timeout_entries">
+    <item msgid="3211660022507486536">"በጭራሽ"</item>
+    <item msgid="7025253383416830453">"ከ1 ደቂቃ በኋላ"</item>
+    <item msgid="1574040255478150028">"ከ5 ደቂቃዎች በኋላ"</item>
+  </string-array>
 </resources>
diff --git a/res/values-de/arrays.xml b/res/values-de/arrays.xml
index c52de95..9a91d6d 100644
--- a/res/values-de/arrays.xml
+++ b/res/values-de/arrays.xml
@@ -586,7 +586,9 @@
     <item msgid="2373999996715432397">"0"</item>
     <item msgid="5305176997036663262">"1"</item>
   </string-array>
-    <!-- no translation found for switch_to_dock_user_when_docked_timeout_entries:0 (3211660022507486536) -->
-    <!-- no translation found for switch_to_dock_user_when_docked_timeout_entries:1 (7025253383416830453) -->
-    <!-- no translation found for switch_to_dock_user_when_docked_timeout_entries:2 (1574040255478150028) -->
+  <string-array name="switch_to_dock_user_when_docked_timeout_entries">
+    <item msgid="3211660022507486536">"Nie"</item>
+    <item msgid="7025253383416830453">"Nach 1 Minute"</item>
+    <item msgid="1574040255478150028">"Nach 5 Minuten"</item>
+  </string-array>
 </resources>
diff --git a/res/values-lv/arrays.xml b/res/values-lv/arrays.xml
index c5ffcd3..0edaf48 100644
--- a/res/values-lv/arrays.xml
+++ b/res/values-lv/arrays.xml
@@ -586,7 +586,9 @@
     <item msgid="2373999996715432397">"0"</item>
     <item msgid="5305176997036663262">"1"</item>
   </string-array>
-    <!-- no translation found for switch_to_dock_user_when_docked_timeout_entries:0 (3211660022507486536) -->
-    <!-- no translation found for switch_to_dock_user_when_docked_timeout_entries:1 (7025253383416830453) -->
-    <!-- no translation found for switch_to_dock_user_when_docked_timeout_entries:2 (1574040255478150028) -->
+  <string-array name="switch_to_dock_user_when_docked_timeout_entries">
+    <item msgid="3211660022507486536">"Nekad"</item>
+    <item msgid="7025253383416830453">"Pēc 1 minūtes"</item>
+    <item msgid="1574040255478150028">"Pēc 5 minūtēm"</item>
+  </string-array>
 </resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 6352c2b..3d8f2f4 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -6416,8 +6416,18 @@
     <string name="battery_tip_limited_temporarily_title">Charging is paused</string>
     <!-- Summary for the battery limited temporarily tip [CHAR LIMIT=NONE] -->
     <string name="battery_tip_limited_temporarily_summary">Protecting battery to extend battery lifespan</string>
-    <!-- Summary for the battery limited temporarily extra tip [CHAR LIMIT=NONE] -->
-    <string name="battery_tip_limited_temporarily_extra_summary"><xliff:g id="percent" example="10%">%1$s</xliff:g></string>
+    <!-- Title for the battery dock defender future bypass tip [CHAR LIMIT=NONE] -->
+    <string name="battery_tip_dock_defender_future_bypass_title">Charging to <xliff:g id="percent" example="10%">%1$s</xliff:g> to protect the battery</string>
+    <!-- Summary for the battery dock defender future bypass tip [CHAR LIMIT=NONE] -->
+    <string name="battery_tip_dock_defender_future_bypass_summary">When your tablet is docked, charging will be paused at <xliff:g id="percent" example="10%">%1$s</xliff:g> to extend battery lifespan</string>
+    <!-- Title for the battery dock defender active tip [CHAR LIMIT=NONE] -->
+    <string name="battery_tip_dock_defender_active_title">Charging paused to protect battery</string>
+    <!-- Summary for the battery dock defender active tip [CHAR LIMIT=NONE] -->
+    <string name="battery_tip_dock_defender_active_summary">When your tablet is docked, charging is paused at <xliff:g id="percent" example="10%">%1$s</xliff:g> to extend battery lifespan</string>
+    <!-- Title for the battery dock defender temporarily bypassed tip [CHAR LIMIT=NONE] -->
+    <string name="battery_tip_dock_defender_temporarily_bypassed_title">Charging to full</string>
+    <!-- Summary for the battery dock defender temporarily bypassed tip [CHAR LIMIT=NONE] -->
+    <string name="battery_tip_dock_defender_temporarily_bypassed_summary">To protect your battery, charging will be paused at <xliff:g id="percent" example="10%">%1$s</xliff:g> the next time your tablet is docked</string>
     <!-- Content description for the battery limited temporarily tip secondary button [CHAR LIMIT=NONE] -->
     <string name="battery_tip_limited_temporarily_sec_button_content_description">Learn more about charging is paused</string>
     <!-- Text of battery limited temporarily tip resume charge button. [CHAR LIMIT=NONE] -->
diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintStatusUtils.java b/src/com/android/settings/biometrics/fingerprint/FingerprintStatusUtils.java
index 18db774..71cdcf7 100644
--- a/src/com/android/settings/biometrics/fingerprint/FingerprintStatusUtils.java
+++ b/src/com/android/settings/biometrics/fingerprint/FingerprintStatusUtils.java
@@ -78,9 +78,7 @@
      * Returns the class name of the Settings page corresponding to fingerprint settings.
      */
     public String getSettingsClassName() {
-        return !hasEnrolled() && isAvailable()
-            ? FingerprintEnrollIntroductionInternal.class.getName()
-            : FingerprintSettings.class.getName();
+        return FingerprintSettings.class.getName();
     }
 
     /**
diff --git a/src/com/android/settings/display/ControlsTrivialPrivacyPreferenceController.java b/src/com/android/settings/display/ControlsTrivialPrivacyPreferenceController.java
index 7239ac7..be2de59 100644
--- a/src/com/android/settings/display/ControlsTrivialPrivacyPreferenceController.java
+++ b/src/com/android/settings/display/ControlsTrivialPrivacyPreferenceController.java
@@ -50,9 +50,11 @@
 
     @Override
     public CharSequence getSummary() {
-        if (getAvailabilityStatus() == DISABLED_DEPENDENT_SETTING) {
+        if (!CustomizableLockScreenUtils.isFeatureEnabled(mContext)
+                && getAvailabilityStatus() == DISABLED_DEPENDENT_SETTING) {
             return mContext.getText(R.string.lockscreen_trivial_disabled_controls_summary);
         }
+
         return mContext.getText(R.string.lockscreen_trivial_controls_summary);
     }
 
@@ -70,21 +72,22 @@
 
     @Override
     public int getAvailabilityStatus() {
-        if (CustomizableLockScreenUtils.isFeatureEnabled(mContext)) {
-            return UNSUPPORTED_ON_DEVICE;
-        }
-
         return showDeviceControlsSettingsEnabled() ? AVAILABLE : DISABLED_DEPENDENT_SETTING;
     }
 
     private boolean showDeviceControlsSettingsEnabled() {
-        return Settings.Secure.getInt(mContext.getContentResolver(), DEPENDENCY_SETTING_KEY, 0)
-                != 0;
+        return CustomizableLockScreenUtils.isFeatureEnabled(mContext)
+                || Settings.Secure.getInt(
+                        mContext.getContentResolver(), DEPENDENCY_SETTING_KEY, 0) != 0;
     }
 
     @Override
     public void displayPreference(PreferenceScreen screen) {
         super.displayPreference(screen);
+        if (CustomizableLockScreenUtils.isFeatureEnabled(mContext)) {
+            return;
+        }
+
         Preference currentPreference = screen.findPreference(getPreferenceKey());
         currentPreference.setDependency("lockscreen_privacy_controls_switch");
     }
diff --git a/src/com/android/settings/fuelgauge/BatteryBroadcastReceiver.java b/src/com/android/settings/fuelgauge/BatteryBroadcastReceiver.java
index 558e0bf..665be1f 100644
--- a/src/com/android/settings/fuelgauge/BatteryBroadcastReceiver.java
+++ b/src/com/android/settings/fuelgauge/BatteryBroadcastReceiver.java
@@ -98,6 +98,7 @@
         final IntentFilter intentFilter = new IntentFilter();
         intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED);
         intentFilter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED);
+        intentFilter.addAction(BatteryUtils.BYPASS_DOCK_DEFENDER_ACTION);
 
         final Intent intent = mContext.registerReceiver(this, intentFilter);
         updateBatteryStatus(intent, true /* forceUpdate */);
@@ -132,6 +133,8 @@
                 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())) {
+                mBatteryListener.onBatteryChanged(BatteryUpdateType.BATTERY_STATUS);
             }
         }
     }
diff --git a/src/com/android/settings/fuelgauge/BatteryInfo.java b/src/com/android/settings/fuelgauge/BatteryInfo.java
index b1e4c34..52d6d58 100644
--- a/src/com/android/settings/fuelgauge/BatteryInfo.java
+++ b/src/com/android/settings/fuelgauge/BatteryInfo.java
@@ -42,6 +42,8 @@
 import com.android.settingslib.utils.PowerUtil;
 import com.android.settingslib.utils.StringUtil;
 
+import java.text.NumberFormat;
+
 public class BatteryInfo {
     private static final String TAG = "BatteryInfo";
 
@@ -49,6 +51,7 @@
     public CharSequence remainingLabel;
     public int batteryLevel;
     public int batteryStatus;
+    public int pluggedStatus;
     public boolean discharging = true;
     public boolean isOverheated;
     public long remainingTimeUs = 0;
@@ -253,7 +256,8 @@
         info.mBatteryUsageStats = batteryUsageStats;
         info.batteryLevel = Utils.getBatteryLevel(batteryBroadcast);
         info.batteryPercentString = Utils.formatPercentage(info.batteryLevel);
-        info.mCharging = batteryBroadcast.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0) != 0;
+        info.pluggedStatus = batteryBroadcast.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0);
+        info.mCharging = info.pluggedStatus != 0;
         info.averageTimeToDischarge = estimate.getAverageDischargeTime();
         info.isOverheated = batteryBroadcast.getIntExtra(
                 BatteryManager.EXTRA_HEALTH, BatteryManager.BATTERY_HEALTH_UNKNOWN)
@@ -280,25 +284,37 @@
                 BatteryManager.BATTERY_STATUS_UNKNOWN);
         info.discharging = false;
         info.suggestionLabel = null;
-        if (info.isOverheated && status != BatteryManager.BATTERY_STATUS_FULL) {
+        int dockDefenderMode = BatteryUtils.getCurrentDockDefenderMode(context, info);
+        if ((info.isOverheated && status != BatteryManager.BATTERY_STATUS_FULL
+                && dockDefenderMode == BatteryUtils.DockDefenderMode.DISABLED)
+                || dockDefenderMode == BatteryUtils.DockDefenderMode.ACTIVE) {
+            // Battery defender active, battery charging paused
             info.remainingLabel = null;
             int chargingLimitedResId = R.string.power_charging_limited;
-            info.chargeLabel =
-                context.getString(chargingLimitedResId, info.batteryPercentString);
-        } else if (chargeTimeMs > 0 && status != BatteryManager.BATTERY_STATUS_FULL) {
+            info.chargeLabel = context.getString(chargingLimitedResId, info.batteryPercentString);
+        } else if ((chargeTimeMs > 0 && status != BatteryManager.BATTERY_STATUS_FULL
+                && dockDefenderMode == BatteryUtils.DockDefenderMode.DISABLED)
+                || dockDefenderMode == BatteryUtils.DockDefenderMode.TEMPORARILY_BYPASSED) {
+            // Battery is charging to full
             info.remainingTimeUs = PowerUtil.convertMsToUs(chargeTimeMs);
-            final CharSequence timeString = StringUtil.formatElapsedTime(
-                    context,
-                    PowerUtil.convertUsToMs(info.remainingTimeUs),
-                    false /* withSeconds */,
+            final CharSequence timeString = StringUtil.formatElapsedTime(context,
+                    (double) PowerUtil.convertUsToMs(info.remainingTimeUs), false /* withSeconds */,
                     true /* collapseTimeUnit */);
             int resId = R.string.power_charging_duration;
-            info.remainingLabel = context.getString(
-                    R.string.power_remaining_charging_duration_only, timeString);
+            info.remainingLabel = context.getString(R.string.power_remaining_charging_duration_only,
+                    timeString);
             info.chargeLabel = context.getString(resId, info.batteryPercentString, timeString);
+        } else if (dockDefenderMode == BatteryUtils.DockDefenderMode.FUTURE_BYPASS) {
+            // Dock defender will be triggered in the future, charging will be paused at 90%.
+            final int extraValue = context.getResources().getInteger(
+                    R.integer.config_battery_extra_tip_value);
+            final String extraPercentage = NumberFormat.getPercentInstance().format(
+                    extraValue * 0.01f);
+            info.chargeLabel = context.getString(R.string.power_charging_future_paused,
+                    info.batteryPercentString, extraPercentage);
         } else {
-            final String chargeStatusLabel =
-                    Utils.getBatteryStatus(context, batteryBroadcast, compactStatus);
+            final String chargeStatusLabel = Utils.getBatteryStatus(context, batteryBroadcast,
+                    compactStatus);
             info.remainingLabel = null;
             info.chargeLabel = info.batteryLevel == 100 ? info.batteryPercentString :
                     resources.getString(R.string.power_charging, info.batteryPercentString,
diff --git a/src/com/android/settings/fuelgauge/BatteryUtils.java b/src/com/android/settings/fuelgauge/BatteryUtils.java
index a6c48a4..e9b72d0 100644
--- a/src/com/android/settings/fuelgauge/BatteryUtils.java
+++ b/src/com/android/settings/fuelgauge/BatteryUtils.java
@@ -24,6 +24,7 @@
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.os.BatteryConsumer;
+import android.os.BatteryManager;
 import android.os.BatteryStats;
 import android.os.BatteryStatsManager;
 import android.os.BatteryUsageStats;
@@ -33,6 +34,7 @@
 import android.os.SystemClock;
 import android.os.UidBatteryConsumer;
 import android.os.UserHandle;
+import android.provider.Settings;
 import android.util.Log;
 
 import androidx.annotation.IntDef;
@@ -72,6 +74,11 @@
     /** Special UID for aggregated other users. */
     public static final long UID_OTHER_USERS = Long.MIN_VALUE;
 
+    /** Flag to check if the dock defender mode has been temporarily bypassed */
+    public static final String SETTINGS_GLOBAL_DOCK_DEFENDER_BYPASS = "dock_defender_bypass";
+
+    public static final String BYPASS_DOCK_DEFENDER_ACTION = "battery.dock.defender.bypass";
+
     @Retention(RetentionPolicy.SOURCE)
     @IntDef({StatusType.SCREEN_USAGE,
             StatusType.FOREGROUND,
@@ -85,6 +92,18 @@
         int ALL = 3;
     }
 
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({DockDefenderMode.FUTURE_BYPASS,
+            DockDefenderMode.ACTIVE,
+            DockDefenderMode.TEMPORARILY_BYPASSED,
+            DockDefenderMode.DISABLED})
+    public @interface DockDefenderMode {
+        int FUTURE_BYPASS = 0;
+        int ACTIVE = 1;
+        int TEMPORARILY_BYPASSED = 2;
+        int DISABLED = 3;
+    }
+
     private static final String TAG = "BatteryUtils";
 
     private static BatteryUtils sInstance;
@@ -570,4 +589,21 @@
 
         return -1L;
     }
+
+    /** Gets the current dock defender mode */
+    public static int getCurrentDockDefenderMode(Context context, BatteryInfo batteryInfo) {
+        if (batteryInfo.pluggedStatus == BatteryManager.BATTERY_PLUGGED_DOCK) {
+            if (Settings.Global.getInt(context.getContentResolver(),
+                    SETTINGS_GLOBAL_DOCK_DEFENDER_BYPASS, 0) == 1) {
+                return DockDefenderMode.TEMPORARILY_BYPASSED;
+            } else if (batteryInfo.isOverheated && FeatureFactory.getFactory(context)
+                    .getPowerUsageFeatureProvider(context)
+                    .isExtraDefend()) {
+                return DockDefenderMode.ACTIVE;
+            } else if (!batteryInfo.isOverheated) {
+                return DockDefenderMode.FUTURE_BYPASS;
+            }
+        }
+        return DockDefenderMode.DISABLED;
+    }
 }
diff --git a/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java b/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java
index 94a93b8..9b6f50f 100644
--- a/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java
+++ b/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java
@@ -147,7 +147,7 @@
     /**
      * Gets a intent for one time bypass charge limited to resume charging.
      */
-    Intent getResumeChargeIntent();
+    Intent getResumeChargeIntent(boolean isDockDefender);
 
     /**
      * Returns battery history data with corresponding timestamp key.
diff --git a/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java b/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java
index 0adfc9d..cc802e8 100644
--- a/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java
+++ b/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java
@@ -156,7 +156,7 @@
     }
 
     @Override
-    public Intent getResumeChargeIntent() {
+    public Intent getResumeChargeIntent(boolean isDockDefender) {
         return null;
     }
 
diff --git a/src/com/android/settings/fuelgauge/batterytip/BatteryTipDialogFragment.java b/src/com/android/settings/fuelgauge/batterytip/BatteryTipDialogFragment.java
index d4c00a4..5fd3905 100644
--- a/src/com/android/settings/fuelgauge/batterytip/BatteryTipDialogFragment.java
+++ b/src/com/android/settings/fuelgauge/batterytip/BatteryTipDialogFragment.java
@@ -43,7 +43,6 @@
 import com.android.settings.fuelgauge.batterytip.tips.RestrictAppTip;
 import com.android.settings.fuelgauge.batterytip.tips.UnrestrictAppTip;
 
-import java.text.NumberFormat;
 import java.util.List;
 
 /**
@@ -142,29 +141,6 @@
                         .setPositiveButton(R.string.battery_tip_unrestrict_app_dialog_ok, this)
                         .setNegativeButton(R.string.battery_tip_unrestrict_app_dialog_cancel, null)
                         .create();
-            case BatteryTip.TipType.BATTERY_DEFENDER:
-                mMetricsFeatureProvider.action(context,
-                        SettingsEnums.ACTION_TIP_BATTERY_DEFENDER, mMetricsKey);
-                final double chargeLimitLevel = 0.8f;
-                final String percentage =
-                        NumberFormat.getPercentInstance().format(chargeLimitLevel);
-                final String message = context.getString(
-                        R.string.battery_tip_limited_temporarily_dialog_msg, percentage);
-                final boolean isPluggedIn = isPluggedIn();
-                final AlertDialog.Builder dialogBuilder =
-                        new AlertDialog.Builder(context)
-                                .setTitle(R.string.battery_tip_limited_temporarily_title)
-                                .setMessage(message);
-                if (isPluggedIn) {
-                    dialogBuilder
-                            .setPositiveButton(
-                                    R.string.battery_tip_limited_temporarily_dialog_resume_charge,
-                                    this)
-                            .setNegativeButton(R.string.okay, null);
-                } else {
-                    dialogBuilder.setPositiveButton(R.string.okay, null);
-                }
-                return dialogBuilder.create();
             default:
                 throw new IllegalArgumentException("unknown type " + mBatteryTip.getType());
         }
diff --git a/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoader.java b/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoader.java
index 95145ba..7bdc5d5 100644
--- a/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoader.java
+++ b/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoader.java
@@ -24,6 +24,7 @@
 import com.android.settings.fuelgauge.BatteryInfo;
 import com.android.settings.fuelgauge.BatteryUtils;
 import com.android.settings.fuelgauge.batterytip.detectors.BatteryDefenderDetector;
+import com.android.settings.fuelgauge.batterytip.detectors.DockDefenderDetector;
 import com.android.settings.fuelgauge.batterytip.detectors.EarlyWarningDetector;
 import com.android.settings.fuelgauge.batterytip.detectors.HighUsageDetector;
 import com.android.settings.fuelgauge.batterytip.detectors.LowBatteryDetector;
@@ -74,6 +75,7 @@
         tips.add(new EarlyWarningDetector(policy, context).detect());
         tips.add(new BatteryDefenderDetector(
                 batteryInfo, context.getApplicationContext()).detect());
+        tips.add(new DockDefenderDetector(batteryInfo, context.getApplicationContext()).detect());
         Collections.sort(tips);
         return tips;
     }
diff --git a/src/com/android/settings/fuelgauge/batterytip/actions/BatteryDefenderAction.java b/src/com/android/settings/fuelgauge/batterytip/actions/BatteryDefenderAction.java
deleted file mode 100644
index 824b6be..0000000
--- a/src/com/android/settings/fuelgauge/batterytip/actions/BatteryDefenderAction.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2020 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.actions;
-
-import android.content.Intent;
-
-import com.android.settings.SettingsActivity;
-import com.android.settings.overlay.FeatureFactory;
-
-/**
- * Action to open the Support Center article
- */
-public class BatteryDefenderAction extends BatteryTipAction {
-    private SettingsActivity mSettingsActivity;
-
-    public BatteryDefenderAction(SettingsActivity settingsActivity) {
-        super(settingsActivity.getApplicationContext());
-        mSettingsActivity = settingsActivity;
-    }
-
-    @Override
-    public void handlePositiveAction(int metricsKey) {
-        final Intent intent = FeatureFactory.getFactory(mContext)
-                .getPowerUsageFeatureProvider(mContext).getResumeChargeIntent();
-        if (intent != null) {
-            mContext.sendBroadcast(intent);
-        }
-    }
-}
diff --git a/src/com/android/settings/fuelgauge/batterytip/detectors/BatteryDefenderDetector.java b/src/com/android/settings/fuelgauge/batterytip/detectors/BatteryDefenderDetector.java
index 87d4a0b..08df2e4 100644
--- a/src/com/android/settings/fuelgauge/batterytip/detectors/BatteryDefenderDetector.java
+++ b/src/com/android/settings/fuelgauge/batterytip/detectors/BatteryDefenderDetector.java
@@ -37,11 +37,10 @@
 
     @Override
     public BatteryTip detect() {
-        if (mBatteryInfo.isOverheated) {
-            final boolean extraDefend = FeatureFactory.getFactory(mContext)
-                    .getPowerUsageFeatureProvider(mContext)
-                    .isExtraDefend();
-            return new BatteryDefenderTip(BatteryTip.StateType.NEW, extraDefend);
+        if (mBatteryInfo.isOverheated && !FeatureFactory.getFactory(mContext)
+                .getPowerUsageFeatureProvider(mContext)
+                .isExtraDefend()) {
+            return new BatteryDefenderTip(BatteryTip.StateType.NEW);
         }
         return new BatteryDefenderTip(BatteryTip.StateType.INVISIBLE);
     }
diff --git a/src/com/android/settings/fuelgauge/batterytip/detectors/DockDefenderDetector.java b/src/com/android/settings/fuelgauge/batterytip/detectors/DockDefenderDetector.java
new file mode 100644
index 0000000..8a839d3
--- /dev/null
+++ b/src/com/android/settings/fuelgauge/batterytip/detectors/DockDefenderDetector.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2022 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 com.android.settings.fuelgauge.BatteryInfo;
+import com.android.settings.fuelgauge.BatteryUtils;
+import com.android.settings.fuelgauge.batterytip.tips.BatteryTip;
+import com.android.settings.fuelgauge.batterytip.tips.DockDefenderTip;
+
+/**
+ * Detect whether the dock defender mode is enabled.
+ */
+public class DockDefenderDetector implements BatteryTipDetector {
+    private final BatteryInfo mBatteryInfo;
+    private final Context mContext;
+
+    public DockDefenderDetector(BatteryInfo batteryInfo, Context context) {
+        mBatteryInfo = batteryInfo;
+        mContext = context;
+    }
+
+    @Override
+    public BatteryTip detect() {
+        int mode = BatteryUtils.getCurrentDockDefenderMode(mContext, mBatteryInfo);
+        return new DockDefenderTip(
+                mode != BatteryUtils.DockDefenderMode.DISABLED
+                        ? BatteryTip.StateType.NEW
+                        : BatteryTip.StateType.INVISIBLE,
+                mode);
+    }
+
+}
diff --git a/src/com/android/settings/fuelgauge/batterytip/tips/BatteryDefenderTip.java b/src/com/android/settings/fuelgauge/batterytip/tips/BatteryDefenderTip.java
index 2fb5650..1ccc29c 100644
--- a/src/com/android/settings/fuelgauge/batterytip/tips/BatteryDefenderTip.java
+++ b/src/com/android/settings/fuelgauge/batterytip/tips/BatteryDefenderTip.java
@@ -32,24 +32,15 @@
 import com.android.settingslib.HelpUtils;
 import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
 
-import java.text.NumberFormat;
-
 /**
  * Tip to show current battery is overheated
  */
 public class BatteryDefenderTip extends BatteryTip {
 
     private static final String TAG = "BatteryDefenderTip";
-    private boolean mExtraDefend = false;
 
     public BatteryDefenderTip(@StateType int state) {
-        this(state, false);
-    }
-
-    public BatteryDefenderTip(@StateType int state, boolean extraDefend) {
-        super(TipType.BATTERY_DEFENDER, state, true /* showDialog */);
-        mExtraDefend = extraDefend;
-        mShowDialog = false;
+        super(TipType.BATTERY_DEFENDER, state, false /* showDialog */);
     }
 
     private BatteryDefenderTip(Parcel in) {
@@ -63,14 +54,6 @@
 
     @Override
     public CharSequence getSummary(Context context) {
-        if (mExtraDefend) {
-            final int extraValue = context.getResources()
-                    .getInteger(R.integer.config_battery_extra_tip_value);
-            final String extraPercentage = NumberFormat.getPercentInstance()
-                    .format(extraValue * 0.01f);
-            return context.getString(
-                    R.string.battery_tip_limited_temporarily_extra_summary, extraPercentage);
-        }
         return context.getString(R.string.battery_tip_limited_temporarily_summary);
     }
 
@@ -131,7 +114,7 @@
         final Intent intent =
                 FeatureFactory.getFactory(context)
                         .getPowerUsageFeatureProvider(context)
-                        .getResumeChargeIntent();
+                        .getResumeChargeIntent(false);
         if (intent != null) {
             context.sendBroadcast(intent);
         }
diff --git a/src/com/android/settings/fuelgauge/batterytip/tips/BatteryTip.java b/src/com/android/settings/fuelgauge/batterytip/tips/BatteryTip.java
index 5aee029..fcf5e09 100644
--- a/src/com/android/settings/fuelgauge/batterytip/tips/BatteryTip.java
+++ b/src/com/android/settings/fuelgauge/batterytip/tips/BatteryTip.java
@@ -58,7 +58,8 @@
             TipType.REDUCED_BATTERY,
             TipType.LOW_BATTERY,
             TipType.REMOVE_APP_RESTRICTION,
-            TipType.BATTERY_DEFENDER})
+            TipType.BATTERY_DEFENDER,
+            TipType.DOCK_DEFENDER})
     public @interface TipType {
         int SMART_BATTERY_MANAGER = 0;
         int APP_RESTRICTION = 1;
@@ -69,6 +70,7 @@
         int SUMMARY = 6;
         int REMOVE_APP_RESTRICTION = 7;
         int BATTERY_DEFENDER = 8;
+        int DOCK_DEFENDER = 9;
     }
 
     @VisibleForTesting
@@ -78,12 +80,13 @@
         TIP_ORDER.append(TipType.BATTERY_SAVER, 0);
         TIP_ORDER.append(TipType.LOW_BATTERY, 1);
         TIP_ORDER.append(TipType.BATTERY_DEFENDER, 2);
-        TIP_ORDER.append(TipType.APP_RESTRICTION, 3);
-        TIP_ORDER.append(TipType.HIGH_DEVICE_USAGE, 4);
-        TIP_ORDER.append(TipType.SUMMARY, 5);
-        TIP_ORDER.append(TipType.SMART_BATTERY_MANAGER, 6);
-        TIP_ORDER.append(TipType.REDUCED_BATTERY, 7);
-        TIP_ORDER.append(TipType.REMOVE_APP_RESTRICTION, 8);
+        TIP_ORDER.append(TipType.DOCK_DEFENDER, 3);
+        TIP_ORDER.append(TipType.APP_RESTRICTION, 4);
+        TIP_ORDER.append(TipType.HIGH_DEVICE_USAGE, 5);
+        TIP_ORDER.append(TipType.SUMMARY, 6);
+        TIP_ORDER.append(TipType.SMART_BATTERY_MANAGER, 7);
+        TIP_ORDER.append(TipType.REDUCED_BATTERY, 8);
+        TIP_ORDER.append(TipType.REMOVE_APP_RESTRICTION, 9);
     }
 
     private static final String KEY_PREFIX = "key_battery_tip";
diff --git a/src/com/android/settings/fuelgauge/batterytip/tips/DockDefenderTip.java b/src/com/android/settings/fuelgauge/batterytip/tips/DockDefenderTip.java
new file mode 100644
index 0000000..2ba3dcd
--- /dev/null
+++ b/src/com/android/settings/fuelgauge/batterytip/tips/DockDefenderTip.java
@@ -0,0 +1,192 @@
+/*
+ * Copyright (C) 2022 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.tips;
+
+import android.app.settings.SettingsEnums;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Parcel;
+import android.util.Log;
+
+import androidx.preference.Preference;
+
+import com.android.settings.R;
+import com.android.settings.fuelgauge.BatteryUtils;
+import com.android.settings.fuelgauge.BatteryUtils.DockDefenderMode;
+import com.android.settings.overlay.FeatureFactory;
+import com.android.settings.widget.CardPreference;
+import com.android.settingslib.HelpUtils;
+import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
+
+import java.text.NumberFormat;
+
+/**
+ * Tip to show dock defender status
+ */
+public class DockDefenderTip extends BatteryTip {
+    private static final String TAG = "DockDefenderTip";
+    private int mMode;
+
+    public DockDefenderTip(@StateType int state, @DockDefenderMode int mode) {
+        super(TipType.DOCK_DEFENDER, state, false);
+        mMode = mode;
+    }
+
+    private DockDefenderTip(Parcel in) {
+        super(in);
+    }
+
+    public int getMode() {
+        return mMode;
+    }
+
+    @Override
+    public CharSequence getTitle(Context context) {
+        switch (mMode) {
+            case DockDefenderMode.FUTURE_BYPASS:
+                return context.getString(R.string.battery_tip_dock_defender_future_bypass_title,
+                        getExtraPercentage(context));
+            case DockDefenderMode.ACTIVE:
+                return context.getString(R.string.battery_tip_dock_defender_active_title);
+            case DockDefenderMode.TEMPORARILY_BYPASSED:
+                return context.getString(
+                        R.string.battery_tip_dock_defender_temporarily_bypassed_title);
+            default:
+                return null;
+        }
+    }
+
+    @Override
+    public CharSequence getSummary(Context context) {
+        switch (mMode) {
+            case DockDefenderMode.FUTURE_BYPASS:
+                return context.getString(R.string.battery_tip_dock_defender_future_bypass_summary,
+                        getExtraPercentage(context));
+            case DockDefenderMode.ACTIVE:
+                return context.getString(R.string.battery_tip_dock_defender_active_summary,
+                        getExtraPercentage(context));
+            case DockDefenderMode.TEMPORARILY_BYPASSED:
+                return context.getString(
+                        R.string.battery_tip_dock_defender_temporarily_bypassed_summary,
+                        getExtraPercentage(context));
+            default:
+                return null;
+        }
+    }
+
+    @Override
+    public int getIconId() {
+        return R.drawable.ic_battery_status_protected_24dp;
+    }
+
+    @Override
+    public void updateState(BatteryTip tip) {
+        mState = tip.mState;
+        if (tip instanceof DockDefenderTip) {
+            mMode = ((DockDefenderTip) tip).mMode;
+        }
+    }
+
+    @Override
+    public void log(Context context, MetricsFeatureProvider metricsFeatureProvider) {
+        metricsFeatureProvider.action(context, SettingsEnums.ACTION_DOCK_DEFENDER_TIP,
+                mState);
+    }
+
+    @Override
+    public void updatePreference(Preference preference) {
+        super.updatePreference(preference);
+        final Context context = preference.getContext();
+
+        CardPreference cardPreference = castToCardPreferenceSafely(preference);
+        if (cardPreference == null) {
+            Log.e(TAG, "cast Preference to CardPreference failed");
+            return;
+        }
+
+        cardPreference.setSelectable(false);
+        switch (mMode) {
+            case DockDefenderMode.FUTURE_BYPASS:
+            case DockDefenderMode.ACTIVE:
+                cardPreference.setPrimaryButtonText(
+                        context.getString(R.string.battery_tip_charge_to_full_button));
+                cardPreference.setPrimaryButtonClickListener(unused -> {
+                    resumeCharging(context);
+                    mMode = DockDefenderMode.TEMPORARILY_BYPASSED;
+                    context.sendBroadcast(new Intent().setAction(
+                            BatteryUtils.BYPASS_DOCK_DEFENDER_ACTION).setPackage(
+                            context.getPackageName()).addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
+                            | Intent.FLAG_RECEIVER_FOREGROUND));
+                    updatePreference(preference);
+                });
+                cardPreference.setPrimaryButtonVisible(true);
+                break;
+            case DockDefenderMode.TEMPORARILY_BYPASSED:
+                cardPreference.setPrimaryButtonVisible(false);
+                break;
+            default:
+                cardPreference.setVisible(false);
+                return;
+        }
+
+        cardPreference.setSecondaryButtonText(context.getString(R.string.learn_more));
+        //TODO: update helper string
+        cardPreference.setSecondaryButtonClickListener(
+                button -> button.startActivityForResult(
+                        HelpUtils.getHelpIntent(
+                                context,
+                                context.getString(R.string.help_url_battery_defender),
+                                /* backupContext */ ""), /* requestCode */ 0));
+        cardPreference.setSecondaryButtonVisible(true);
+        cardPreference.setSecondaryButtonContentDescription(context.getString(
+                R.string.battery_tip_limited_temporarily_sec_button_content_description));
+
+    }
+
+    private CardPreference castToCardPreferenceSafely(Preference preference) {
+        return preference instanceof CardPreference ? (CardPreference) preference : null;
+    }
+
+    private void resumeCharging(Context context) {
+        final Intent intent =
+                FeatureFactory.getFactory(context)
+                        .getPowerUsageFeatureProvider(context)
+                        .getResumeChargeIntent(true);
+        if (intent != null) {
+            context.sendBroadcast(intent);
+        }
+
+        Log.i(TAG, "send resume charging broadcast intent=" + intent);
+    }
+
+    private String getExtraPercentage(Context context) {
+        final int extraValue = context.getResources()
+                .getInteger(R.integer.config_battery_extra_tip_value);
+        return NumberFormat.getPercentInstance()
+                .format(extraValue * 0.01f);
+    }
+
+    public static final Creator CREATOR = new Creator() {
+        public BatteryTip createFromParcel(Parcel in) {
+            return new DockDefenderTip(in);
+        }
+
+        public BatteryTip[] newArray(int size) {
+            return new DockDefenderTip[size];
+        }
+    };
+}
diff --git a/src/com/android/settings/fuelgauge/batteryusage/PowerUsageAdvanced.java b/src/com/android/settings/fuelgauge/batteryusage/PowerUsageAdvanced.java
index b88d85d..db90473 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/PowerUsageAdvanced.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/PowerUsageAdvanced.java
@@ -55,7 +55,6 @@
     private static final String KEY_REFRESH_TYPE = "refresh_type";
     private static final String KEY_BATTERY_GRAPH = "battery_graph";
     private static final String KEY_APP_LIST = "app_list";
-    private static final int LOADER_BATTERY_USAGE_STATS = 2;
 
     @VisibleForTesting
     BatteryHistoryPreference mHistPref;
@@ -188,7 +187,7 @@
         // Uses customized battery history loader if chart design is enabled.
         if (mIsChartGraphEnabled && !mIsChartDataLoaded) {
             mIsChartDataLoaded = true;
-            getLoaderManager().restartLoader(LOADER_BATTERY_USAGE_STATS, bundle,
+            restartLoader(LoaderIndex.BATTERY_HISTORY_LOADER, bundle,
                     mBatteryHistoryLoaderCallbacks);
         } else if (!mIsChartGraphEnabled) {
             super.restartBatteryStatsLoader(refreshType);
diff --git a/src/com/android/settings/fuelgauge/batteryusage/PowerUsageBase.java b/src/com/android/settings/fuelgauge/batteryusage/PowerUsageBase.java
index ccefdf2..ed3a921 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/PowerUsageBase.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/PowerUsageBase.java
@@ -24,6 +24,7 @@
 import android.os.UserManager;
 import android.util.Log;
 
+import androidx.annotation.IntDef;
 import androidx.annotation.NonNull;
 import androidx.annotation.VisibleForTesting;
 import androidx.loader.app.LoaderManager;
@@ -33,17 +34,19 @@
 import com.android.settings.fuelgauge.BatteryBroadcastReceiver;
 import com.android.settings.fuelgauge.BatteryUtils;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
 /**
  * Common base class for things that need to show the battery usage graph.
  */
 public abstract class PowerUsageBase extends DashboardFragment {
-
     private static final String TAG = "PowerUsageBase";
-    private static final String KEY_REFRESH_TYPE = "refresh_type";
-    private static final String KEY_INCLUDE_HISTORY = "include_history";
 
-    private static final int LOADER_BATTERY_USAGE_STATS = 1;
-
+    @VisibleForTesting
+    static final String KEY_REFRESH_TYPE = "refresh_type";
+    @VisibleForTesting
+    static final String KEY_INCLUDE_HISTORY = "include_history";
     @VisibleForTesting
     BatteryUsageStats mBatteryUsageStats;
 
@@ -55,6 +58,21 @@
     final BatteryUsageStatsLoaderCallbacks mBatteryUsageStatsLoaderCallbacks =
             new BatteryUsageStatsLoaderCallbacks();
 
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({
+            LoaderIndex.BATTERY_USAGE_STATS_LOADER,
+            LoaderIndex.BATTERY_INFO_LOADER,
+            LoaderIndex.BATTERY_TIP_LOADER,
+            LoaderIndex.BATTERY_HISTORY_LOADER
+
+    })
+    public @interface LoaderIndex {
+        int BATTERY_USAGE_STATS_LOADER = 0;
+        int BATTERY_INFO_LOADER = 1;
+        int BATTERY_TIP_LOADER = 2;
+        int BATTERY_HISTORY_LOADER = 3;
+    }
+
     @Override
     public void onAttach(Activity activity) {
         super.onAttach(activity);
@@ -91,10 +109,28 @@
         final Bundle bundle = new Bundle();
         bundle.putInt(KEY_REFRESH_TYPE, refreshType);
         bundle.putBoolean(KEY_INCLUDE_HISTORY, isBatteryHistoryNeeded());
-        getLoaderManager().restartLoader(LOADER_BATTERY_USAGE_STATS, bundle,
+        restartLoader(LoaderIndex.BATTERY_USAGE_STATS_LOADER, bundle,
                 mBatteryUsageStatsLoaderCallbacks);
     }
 
+    protected LoaderManager getLoaderManagerForCurrentFragment() {
+        return LoaderManager.getInstance(this);
+    }
+
+    protected void restartLoader(int loaderId, Bundle bundle,
+            LoaderManager.LoaderCallbacks<?> loaderCallbacks) {
+        LoaderManager loaderManager = getLoaderManagerForCurrentFragment();
+        Loader<?> loader = loaderManager.getLoader(
+                loaderId);
+        if (loader != null && !loader.isReset()) {
+            loaderManager.restartLoader(loaderId, bundle,
+                    loaderCallbacks);
+        } else {
+            loaderManager.initLoader(loaderId, bundle,
+                    loaderCallbacks);
+        }
+    }
+
     protected void onLoadFinished(@BatteryUpdateType int refreshType) {
         refreshUi(refreshType);
     }
diff --git a/src/com/android/settings/fuelgauge/batteryusage/PowerUsageSummary.java b/src/com/android/settings/fuelgauge/batteryusage/PowerUsageSummary.java
index bca32a7..f266492 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/PowerUsageSummary.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/PowerUsageSummary.java
@@ -65,11 +65,6 @@
     static final String KEY_BATTERY_USAGE = "battery_usage_summary";
 
     @VisibleForTesting
-    static final int BATTERY_INFO_LOADER = 1;
-    @VisibleForTesting
-    static final int BATTERY_TIP_LOADER = 2;
-
-    @VisibleForTesting
     PowerUsageFeatureProvider mPowerFeatureProvider;
     @VisibleForTesting
     BatteryUtils mBatteryUtils;
@@ -241,7 +236,7 @@
 
     @VisibleForTesting
     void restartBatteryTipLoader() {
-        getLoaderManager().restartLoader(BATTERY_TIP_LOADER, Bundle.EMPTY, mBatteryTipsCallbacks);
+        restartLoader(LoaderIndex.BATTERY_TIP_LOADER, Bundle.EMPTY, mBatteryTipsCallbacks);
     }
 
     @VisibleForTesting
@@ -274,8 +269,7 @@
         if (!mIsBatteryPresent) {
             return;
         }
-        getLoaderManager().restartLoader(BATTERY_INFO_LOADER, Bundle.EMPTY,
-                mBatteryInfoLoaderCallbacks);
+        restartLoader(LoaderIndex.BATTERY_INFO_LOADER, Bundle.EMPTY, mBatteryInfoLoaderCallbacks);
     }
 
     @VisibleForTesting
diff --git a/src/com/android/settings/homepage/SettingsHomepageActivity.java b/src/com/android/settings/homepage/SettingsHomepageActivity.java
index 6739084..b79a64c 100644
--- a/src/com/android/settings/homepage/SettingsHomepageActivity.java
+++ b/src/com/android/settings/homepage/SettingsHomepageActivity.java
@@ -27,6 +27,8 @@
 import android.app.settings.SettingsEnums;
 import android.content.ComponentName;
 import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.PackageManager;
 import android.content.pm.UserInfo;
 import android.content.res.Configuration;
 import android.os.Bundle;
@@ -66,6 +68,7 @@
 import com.android.settings.core.FeatureFlags;
 import com.android.settings.homepage.contextualcards.ContextualCardsFragment;
 import com.android.settings.overlay.FeatureFactory;
+import com.android.settings.password.PasswordUtils;
 import com.android.settings.safetycenter.SafetyCenterManagerWrapper;
 import com.android.settingslib.Utils;
 import com.android.settingslib.core.lifecycle.HideNonSystemOverlayMixin;
@@ -444,6 +447,32 @@
             finish();
             return;
         }
+
+        if (!TextUtils.equals(PasswordUtils.getCallingAppPackageName(getActivityToken()),
+                getPackageName())) {
+            ActivityInfo targetActivityInfo = null;
+            try {
+                targetActivityInfo = getPackageManager().getActivityInfo(targetComponentName,
+                        /* flags= */ 0);
+            } catch (PackageManager.NameNotFoundException e) {
+                Log.e(TAG, "Failed to get target ActivityInfo: " + e);
+                finish();
+                return;
+            }
+
+            if (!targetActivityInfo.exported) {
+                Log.e(TAG, "Must not launch an unexported Actvity for deep link");
+                finish();
+                return;
+            }
+
+            if (!isCallingAppPermitted(targetActivityInfo.permission)) {
+                Log.e(TAG, "Calling app must have the permission of deep link Activity");
+                finish();
+                return;
+            }
+        }
+
         targetIntent.setComponent(targetComponentName);
 
         // To prevent launchDeepLinkIntentToRight again for configuration change.
@@ -485,6 +514,12 @@
         }
     }
 
+    @VisibleForTesting
+    boolean isCallingAppPermitted(String permission) {
+        return TextUtils.isEmpty(permission) || PasswordUtils.isCallingAppPermitted(
+                this, getActivityToken(), permission);
+    }
+
     private String getHighlightMenuKey() {
         final Intent intent = getIntent();
         if (intent != null && TextUtils.equals(intent.getAction(),
diff --git a/tests/robotests/src/com/android/settings/display/ControlsTrivialPrivacyPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/display/ControlsTrivialPrivacyPreferenceControllerTest.java
index 3d4bc2e..8bb3ff6 100644
--- a/tests/robotests/src/com/android/settings/display/ControlsTrivialPrivacyPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/display/ControlsTrivialPrivacyPreferenceControllerTest.java
@@ -21,10 +21,14 @@
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
 
 import android.content.ContentResolver;
 import android.content.Context;
+import android.database.Cursor;
+import android.database.MatrixCursor;
 import android.provider.Settings;
 
 import androidx.preference.Preference;
@@ -40,6 +44,7 @@
 import org.mockito.Mock;
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
+import org.mockito.stubbing.Answer;
 import org.robolectric.RobolectricTestRunner;
 
 @RunWith(RobolectricTestRunner.class)
@@ -62,9 +67,11 @@
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
-        mContext = ApplicationProvider.getApplicationContext();
+        mContext = spy(ApplicationProvider.getApplicationContext());
+        mContentResolver = spy(mContext.getContentResolver());
+        when(mContext.getContentResolver()).thenReturn(mContentResolver);
 
-        mContentResolver = mContext.getContentResolver();
+        setCustomizableLockScreenQuickAffordancesEnabled(false);
 
         mController = new ControlsTrivialPrivacyPreferenceController(mContext, TEST_KEY);
     }
@@ -131,6 +138,18 @@
     }
 
     @Test
+    public void updateStateWithCustomizableLockScreenQuickAffordancesEnabled() {
+        setCustomizableLockScreenQuickAffordancesEnabled(true);
+        Settings.Secure.putInt(mContentResolver, DEPENDENCY_SETTING_KEY, 0);
+
+        mController.updateState(mPreference);
+
+        verify(mPreference).setEnabled(true);
+        verify(mPreference, atLeastOnce()).setSummary(
+                mContext.getString(R.string.lockscreen_trivial_controls_summary));
+    }
+
+    @Test
     public void getAvailabilityStatusWithoutDeviceControls() {
         Settings.Secure.putInt(mContentResolver, DEPENDENCY_SETTING_KEY, 0);
 
@@ -139,6 +158,15 @@
     }
 
     @Test
+    public void getAvailabilityStatusWithCustomizableLockScreenQuickAffordancesEnabled() {
+        setCustomizableLockScreenQuickAffordancesEnabled(true);
+        Settings.Secure.putInt(mContentResolver, DEPENDENCY_SETTING_KEY, 0);
+
+        assertThat(mController.getAvailabilityStatus()).isEqualTo(
+                BasePreferenceController.AVAILABLE);
+    }
+
+    @Test
     public void getAvailabilityStatusWithDeviceControls() {
         Settings.Secure.putInt(mContentResolver, DEPENDENCY_SETTING_KEY, 1);
 
@@ -154,4 +182,22 @@
         mController.displayPreference(mPreferenceScreen);
         verify(mPreference).setDependency(anyString());
     }
+
+    private void setCustomizableLockScreenQuickAffordancesEnabled(boolean isEnabled) {
+        when(
+                mContentResolver.query(
+                        CustomizableLockScreenUtils.FLAGS_URI, null, null, null))
+                .thenAnswer((Answer<Cursor>) invocation -> {
+                    final MatrixCursor cursor = new MatrixCursor(
+                            new String[] {
+                                    CustomizableLockScreenUtils.NAME,
+                                    CustomizableLockScreenUtils.VALUE
+                            });
+                    cursor.addRow(
+                            new Object[] {
+                                    CustomizableLockScreenUtils.ENABLED_FLAG, isEnabled ? 1 : 0
+                            });
+                    return cursor;
+                });
+    }
 }
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryBroadcastReceiverTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryBroadcastReceiverTest.java
index 867d8f4..79bd84b 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryBroadcastReceiverTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryBroadcastReceiverTest.java
@@ -55,6 +55,7 @@
     private BatteryBroadcastReceiver mBatteryBroadcastReceiver;
     private Context mContext;
     private Intent mChargingIntent;
+    private Intent mDockDefenderBypassIntent;
 
     @Before
     public void setUp() {
@@ -72,6 +73,8 @@
         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
@@ -131,6 +134,13 @@
     }
 
     @Test
+    public void testOnReceive_dockDefenderBypassed_listenerInvoked() {
+        mBatteryBroadcastReceiver.onReceive(mContext, mDockDefenderBypassIntent);
+
+        verify(mBatteryListener).onBatteryChanged(BatteryUpdateType.BATTERY_STATUS);
+    }
+
+    @Test
     public void testRegister_updateBatteryStatus() {
         doReturn(mChargingIntent).when(mContext).registerReceiver(any(), any());
 
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryInfoTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryInfoTest.java
index c5c47d2..209dc89 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryInfoTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryInfoTest.java
@@ -36,6 +36,7 @@
 import android.os.BatteryStats;
 import android.os.BatteryUsageStats;
 import android.os.SystemClock;
+import android.provider.Settings;
 import android.util.SparseIntArray;
 
 import com.android.internal.os.BatteryStatsHistoryIterator;
@@ -66,6 +67,7 @@
     private static final String STATUS_CHARGING_NO_TIME = "50% - charging";
     private static final String STATUS_CHARGING_TIME = "50% - 0 min left until full";
     private static final String STATUS_NOT_CHARGING = "Not charging";
+    private static final String STATUS_CHARGING_FUTURE_BYPASS = "50% - Charging to 12%";
     private static final long REMAINING_TIME_NULL = -1;
     private static final long REMAINING_TIME = 2;
     // Strings are defined in frameworks/base/packages/SettingsLib/res/values/strings.xml
@@ -97,6 +99,10 @@
         mDisChargingBatteryBroadcast = BatteryTestUtils.getDischargingIntent();
 
         mChargingBatteryBroadcast = BatteryTestUtils.getChargingIntent();
+
+        doReturn(false).when(mFeatureFactory.powerUsageFeatureProvider).isExtraDefend();
+        Settings.Global.putInt(mContext.getContentResolver(),
+                BatteryUtils.SETTINGS_GLOBAL_DOCK_DEFENDER_BYPASS, 0);
     }
 
     @Test
@@ -231,6 +237,7 @@
         BatteryInfo info = BatteryInfo.getBatteryInfo(mContext, mChargingBatteryBroadcast,
                 mBatteryUsageStats, MOCK_ESTIMATE, SystemClock.elapsedRealtime() * 1000,
                 false /* shortString */);
+
         assertThat(info.remainingTimeUs).isEqualTo(TEST_CHARGE_TIME_REMAINING);
         assertThat(info.remainingLabel.toString())
                 .isEqualTo(TEST_CHARGE_TIME_REMAINING_STRINGIFIED);
@@ -265,6 +272,62 @@
         assertThat(info.chargeLabel.toString()).contains(expectedString);
     }
 
+    @Test
+    public void testGetBatteryInfo_dockDefenderActive_updateChargeString() {
+        final String expectedString =
+                mContext.getString(R.string.battery_tip_limited_temporarily_title);
+        doReturn(TEST_CHARGE_TIME_REMAINING / 1000)
+                .when(mBatteryUsageStats).getChargeTimeRemainingMs();
+        doReturn(true).when(mFeatureFactory.powerUsageFeatureProvider).isExtraDefend();
+        Intent intent = BatteryTestUtils.getCustomBatteryIntent(BatteryManager.BATTERY_PLUGGED_DOCK,
+                        50 /* level */,
+                        100 /* scale */,
+                        BatteryManager.BATTERY_STATUS_CHARGING)
+                .putExtra(BatteryManager.EXTRA_HEALTH, BatteryManager.BATTERY_HEALTH_OVERHEAT);
+
+        BatteryInfo info = BatteryInfo.getBatteryInfo(mContext, intent,
+                mBatteryUsageStats, MOCK_ESTIMATE, SystemClock.elapsedRealtime() * 1000,
+                false /* shortString */);
+
+        assertThat(info.chargeLabel.toString()).contains(expectedString);
+    }
+
+    @Test
+    public void testGetBatteryInfo_dockDefenderTemporarilyBypassed_updateChargeLabel() {
+        doReturn(REMAINING_TIME).when(mBatteryUsageStats).getChargeTimeRemainingMs();
+        mChargingBatteryBroadcast
+                .putExtra(BatteryManager.EXTRA_HEALTH, BatteryManager.BATTERY_HEALTH_GOOD);
+        Settings.Global.putInt(mContext.getContentResolver(),
+                BatteryUtils.SETTINGS_GLOBAL_DOCK_DEFENDER_BYPASS, 1);
+
+        BatteryInfo info = BatteryInfo.getBatteryInfo(mContext,
+                BatteryTestUtils.getCustomBatteryIntent(BatteryManager.BATTERY_PLUGGED_DOCK,
+                        50 /* level */,
+                        100 /* scale */,
+                        BatteryManager.BATTERY_STATUS_CHARGING),
+                mBatteryUsageStats, MOCK_ESTIMATE, SystemClock.elapsedRealtime() * 1000,
+                false /* shortString */);
+
+        assertThat(info.chargeLabel.toString()).contains(STATUS_CHARGING_TIME);
+    }
+
+    @Test
+    public void testGetBatteryInfo_dockDefenderFutureBypass_updateChargeLabel() {
+        doReturn(false).when(mFeatureFactory.powerUsageFeatureProvider).isExtraDefend();
+        mChargingBatteryBroadcast
+                .putExtra(BatteryManager.EXTRA_HEALTH, BatteryManager.BATTERY_HEALTH_GOOD);
+
+        BatteryInfo info = BatteryInfo.getBatteryInfo(mContext,
+                BatteryTestUtils.getCustomBatteryIntent(BatteryManager.BATTERY_PLUGGED_DOCK,
+                        50 /* level */,
+                        100 /* scale */,
+                        BatteryManager.BATTERY_STATUS_CHARGING),
+                mBatteryUsageStats, MOCK_ESTIMATE, SystemClock.elapsedRealtime() * 1000,
+                false /* shortString */);
+
+        assertThat(info.chargeLabel.toString()).contains(STATUS_CHARGING_FUTURE_BYPASS);
+    }
+
     // Make our battery stats return a sequence of battery events.
     private void mockBatteryStatsHistory() {
         // Mock out new data every time iterateBatteryStatsHistory is called.
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImplTest.java b/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImplTest.java
index 66a5e7f..648685a 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImplTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImplTest.java
@@ -132,7 +132,12 @@
     }
 
     @Test
-    public void testGetResumeChargeIntent_returnNull() {
-        assertThat(mPowerFeatureProvider.getResumeChargeIntent()).isNull();
+    public void testGetResumeChargeIntentWithoutDockDefender_returnNull() {
+        assertThat(mPowerFeatureProvider.getResumeChargeIntent(false)).isNull();
+    }
+
+    @Test
+    public void testGetResumeChargeIntentWithDockDefender_returnNull() {
+        assertThat(mPowerFeatureProvider.getResumeChargeIntent(true)).isNull();
     }
 }
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipDialogFragmentTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipDialogFragmentTest.java
index db1159e..c5d66a6 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipDialogFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipDialogFragmentTest.java
@@ -244,20 +244,4 @@
         assertThat(shadowDialog.getMessage()).isEqualTo(
                 mContext.getText(R.string.battery_tip_dialog_summary_message));
     }
-
-    @Test
-    public void testOnCreateDialog_defenderTip_fireDialog() {
-        mDialogFragment = BatteryTipDialogFragment.newInstance(mDefenderTip, METRICS_KEY);
-
-        FragmentController.setupFragment(mDialogFragment, FragmentActivity.class,
-                0 /* containerViewId */, null /* bundle */);
-
-        final AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
-        ShadowAlertDialogCompat shadowDialog = ShadowAlertDialogCompat.shadowOf(dialog);
-
-        assertThat(shadowDialog.getTitle()).isEqualTo(
-                mContext.getString(R.string.battery_tip_limited_temporarily_title));
-        assertThat(shadowDialog.getMessage()).isEqualTo(
-                mContext.getString(R.string.battery_tip_limited_temporarily_dialog_msg, "80%"));
-    }
 }
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 95280b6..6d3965e 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.BATTERY_SAVER,
             BatteryTip.TipType.LOW_BATTERY,
             BatteryTip.TipType.BATTERY_DEFENDER,
+            BatteryTip.TipType.DOCK_DEFENDER,
             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/BatteryDefenderDetectorTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/BatteryDefenderDetectorTest.java
index 90e7ad7..f81a4be 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/BatteryDefenderDetectorTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/BatteryDefenderDetectorTest.java
@@ -18,10 +18,15 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+
 import androidx.test.core.app.ApplicationProvider;
 
 import com.android.settings.fuelgauge.BatteryInfo;
 import com.android.settings.fuelgauge.batterytip.tips.BatteryTip;
+import com.android.settings.testutils.FakeFeatureFactory;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -36,6 +41,9 @@
     @Mock
     private BatteryInfo mBatteryInfo;
     private BatteryDefenderDetector mBatteryDefenderDetector;
+    private Context mContext;
+
+    private FakeFeatureFactory mFakeFeatureFactory;
 
     @Before
     public void setUp() {
@@ -43,20 +51,42 @@
 
         mBatteryInfo.discharging = false;
 
+        mContext = ApplicationProvider.getApplicationContext();
+
         mBatteryDefenderDetector = new BatteryDefenderDetector(
-            mBatteryInfo, ApplicationProvider.getApplicationContext());
+            mBatteryInfo, mContext);
+
+        mFakeFeatureFactory = FakeFeatureFactory.setupForTest();
     }
 
     @Test
-    public void testDetect_notOverheated_tipInvisible() {
+    public void testDetect_notOverheatedNotExtraDefend_tipInvisible() {
         mBatteryInfo.isOverheated = false;
+        when(mFakeFeatureFactory.powerUsageFeatureProvider.isExtraDefend()).thenReturn(false);
 
         assertThat(mBatteryDefenderDetector.detect().isVisible()).isFalse();
     }
 
     @Test
-    public void testDetect_isOverheated_tipNew() {
+    public void testDetect_notOverheatedIsExtraDefend_tipInvisible() {
+        mBatteryInfo.isOverheated = false;
+        when(mFakeFeatureFactory.powerUsageFeatureProvider.isExtraDefend()).thenReturn(true);
+
+        assertThat(mBatteryDefenderDetector.detect().isVisible()).isFalse();
+    }
+
+    @Test
+    public void testDetect_isOverheatedIsExtraDefend_tipInvisible() {
+        mBatteryInfo.isOverheated = false;
+        when(mFakeFeatureFactory.powerUsageFeatureProvider.isExtraDefend()).thenReturn(true);
+
+        assertThat(mBatteryDefenderDetector.detect().isVisible()).isFalse();
+    }
+
+    @Test
+    public void testDetect_isOverheatedNotExtraDefend_tipNew() {
         mBatteryInfo.isOverheated = true;
+        when(mFakeFeatureFactory.powerUsageFeatureProvider.isExtraDefend()).thenReturn(false);
 
         assertThat(mBatteryDefenderDetector.detect().getState())
                 .isEqualTo(BatteryTip.StateType.NEW);
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/DockDefenderDetectorTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/DockDefenderDetectorTest.java
new file mode 100644
index 0000000..9652a00
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/DockDefenderDetectorTest.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2022 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 org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.refEq;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.BatteryManager;
+import android.provider.Settings;
+
+import androidx.test.core.app.ApplicationProvider;
+
+import com.android.settings.fuelgauge.BatteryInfo;
+import com.android.settings.fuelgauge.BatteryUtils;
+import com.android.settings.fuelgauge.batterytip.tips.BatteryTip;
+import com.android.settings.fuelgauge.batterytip.tips.DockDefenderTip;
+import com.android.settings.testutils.BatteryTestUtils;
+import com.android.settings.testutils.FakeFeatureFactory;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+
+@RunWith(RobolectricTestRunner.class)
+public class DockDefenderDetectorTest {
+
+    private BatteryInfo mBatteryInfo;
+    private DockDefenderDetector mDockDefenderDetector;
+    private Context mContext;
+    private FakeFeatureFactory mFakeFeatureFactory;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mContext = spy(ApplicationProvider.getApplicationContext());
+        mBatteryInfo = new BatteryInfo();
+        mBatteryInfo.pluggedStatus = BatteryManager.BATTERY_PLUGGED_DOCK;
+        mDockDefenderDetector = new DockDefenderDetector(mBatteryInfo, mContext);
+        Intent intent = BatteryTestUtils.getCustomBatteryIntent(BatteryManager.BATTERY_PLUGGED_DOCK,
+                50 /* level */, 100 /* scale */, BatteryManager.BATTERY_STATUS_CHARGING);
+        doReturn(intent).when(mContext).registerReceiver(eq(null),
+                refEq(new IntentFilter(Intent.ACTION_BATTERY_CHANGED)));
+
+        Settings.Global.putInt(mContext.getContentResolver(),
+                BatteryUtils.SETTINGS_GLOBAL_DOCK_DEFENDER_BYPASS, 0);
+        mFakeFeatureFactory = FakeFeatureFactory.setupForTest();
+    }
+
+    @Test
+    public void testDetect_dockDefenderTemporarilyBypassed() {
+        Settings.Global.putInt(mContext.getContentResolver(),
+                BatteryUtils.SETTINGS_GLOBAL_DOCK_DEFENDER_BYPASS, 1);
+
+        BatteryTip batteryTip = mDockDefenderDetector.detect();
+
+        assertTrue(batteryTip instanceof DockDefenderTip);
+        assertEquals(((DockDefenderTip) batteryTip).getMode(),
+                BatteryUtils.DockDefenderMode.TEMPORARILY_BYPASSED);
+    }
+
+    @Test
+    public void testDetect_dockDefenderActive() {
+        mBatteryInfo.isOverheated = true;
+        doReturn(true).when(mFakeFeatureFactory.powerUsageFeatureProvider).isExtraDefend();
+
+        BatteryTip batteryTip = mDockDefenderDetector.detect();
+
+        assertTrue(batteryTip instanceof DockDefenderTip);
+        assertEquals(((DockDefenderTip) batteryTip).getMode(),
+                BatteryUtils.DockDefenderMode.ACTIVE);
+    }
+
+    @Test
+    public void testDetect_dockDefenderFutureBypass() {
+        mBatteryInfo.isOverheated = false;
+        doReturn(false).when(mFakeFeatureFactory.powerUsageFeatureProvider).isExtraDefend();
+
+        BatteryTip batteryTip = mDockDefenderDetector.detect();
+
+        assertTrue(batteryTip instanceof DockDefenderTip);
+        assertEquals(((DockDefenderTip) batteryTip).getMode(),
+                BatteryUtils.DockDefenderMode.FUTURE_BYPASS);
+    }
+
+    @Test
+    public void testDetect_overheatedTrue_dockDefenderDisabled() {
+        mBatteryInfo.isOverheated = true;
+        doReturn(false).when(mFakeFeatureFactory.powerUsageFeatureProvider).isExtraDefend();
+
+        BatteryTip batteryTip = mDockDefenderDetector.detect();
+
+        assertTrue(batteryTip instanceof DockDefenderTip);
+        assertEquals(((DockDefenderTip) batteryTip).getMode(),
+                BatteryUtils.DockDefenderMode.DISABLED);
+    }
+
+    @Test
+    public void testDetect_pluggedInAC_dockDefenderDisabled() {
+        mBatteryInfo.pluggedStatus = BatteryManager.BATTERY_PLUGGED_AC;
+
+        BatteryTip batteryTip = mDockDefenderDetector.detect();
+
+        assertTrue(batteryTip instanceof DockDefenderTip);
+        assertEquals(((DockDefenderTip) batteryTip).getMode(),
+                BatteryUtils.DockDefenderMode.DISABLED);
+    }
+
+    @Test
+    public void testDetect_overheatedTrueAndDockDefenderNotTriggered_dockDefenderDisabled() {
+        doReturn(false).when(mFakeFeatureFactory.powerUsageFeatureProvider).isExtraDefend();
+        mBatteryInfo.isOverheated = true;
+
+        BatteryTip batteryTip = mDockDefenderDetector.detect();
+
+        assertTrue(batteryTip instanceof DockDefenderTip);
+        assertEquals(((DockDefenderTip) batteryTip).getMode(),
+                BatteryUtils.DockDefenderMode.DISABLED);
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/BatteryDefenderTipTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/BatteryDefenderTipTest.java
index 6bd6b26..8b6033a 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/BatteryDefenderTipTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/BatteryDefenderTipTest.java
@@ -79,20 +79,12 @@
     }
 
     @Test
-    public void getSummary_notExtraDefended_showNonExtraDefendedSummary() {
+    public void getSummary_showSummary() {
         assertThat(mBatteryDefenderTip.getSummary(mContext))
                 .isEqualTo(mContext.getString(R.string.battery_tip_limited_temporarily_summary));
     }
 
     @Test
-    public void getSummary_extraDefended_showExtraDefendedSummary() {
-        BatteryDefenderTip defenderTip = new BatteryDefenderTip(
-                BatteryTip.StateType.NEW, /* extraDefended= */ true);
-
-        assertThat(defenderTip.getSummary(mContext).toString()).isEqualTo("12%");
-    }
-
-    @Test
     public void getIcon_showIcon() {
         assertThat(mBatteryDefenderTip.getIconId())
                 .isEqualTo(R.drawable.ic_battery_status_good_24dp);
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/DockDefenderTipTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/DockDefenderTipTest.java
new file mode 100644
index 0000000..d917d89
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/DockDefenderTipTest.java
@@ -0,0 +1,195 @@
+/*
+ * Copyright (C) 2022 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.tips;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+
+import android.app.settings.SettingsEnums;
+import android.content.Context;
+import android.util.Log;
+
+import androidx.preference.Preference;
+import androidx.test.core.app.ApplicationProvider;
+
+import com.android.settings.R;
+import com.android.settings.fuelgauge.BatteryUtils;
+import com.android.settings.testutils.FakeFeatureFactory;
+import com.android.settings.widget.CardPreference;
+import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
+
+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.shadows.ShadowLog;
+
+import java.text.NumberFormat;
+
+@RunWith(RobolectricTestRunner.class)
+public class DockDefenderTipTest {
+    private Context mContext;
+    private DockDefenderTip mDockDefenderTipFutureBypass;
+    private DockDefenderTip mDockDefenderTipActive;
+    private DockDefenderTip mDockDefenderTipTemporarilyBypassed;
+    private DockDefenderTip mDockDefenderTipDisabled;
+    private FakeFeatureFactory mFeatureFactory;
+    private MetricsFeatureProvider mMetricsFeatureProvider;
+
+    @Mock
+    private Preference mPreference;
+    @Mock
+    private CardPreference mCardPreference;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+
+        mContext = ApplicationProvider.getApplicationContext();
+        mFeatureFactory = FakeFeatureFactory.setupForTest();
+        mMetricsFeatureProvider = mFeatureFactory.metricsFeatureProvider;
+
+        mDockDefenderTipFutureBypass = new DockDefenderTip(BatteryTip.StateType.NEW,
+                BatteryUtils.DockDefenderMode.FUTURE_BYPASS);
+        mDockDefenderTipActive = new DockDefenderTip(BatteryTip.StateType.NEW,
+                BatteryUtils.DockDefenderMode.ACTIVE);
+        mDockDefenderTipTemporarilyBypassed = new DockDefenderTip(BatteryTip.StateType.NEW,
+                BatteryUtils.DockDefenderMode.TEMPORARILY_BYPASSED);
+        mDockDefenderTipDisabled = new DockDefenderTip(BatteryTip.StateType.INVISIBLE,
+                BatteryUtils.DockDefenderMode.DISABLED);
+
+        doReturn(mContext).when(mPreference).getContext();
+        doReturn(mContext).when(mCardPreference).getContext();
+    }
+
+    @Test
+    public void testGetTitle() {
+        assertThat(mDockDefenderTipFutureBypass.getTitle(mContext).toString()).isEqualTo(
+                mContext.getString(R.string.battery_tip_dock_defender_future_bypass_title,
+                        getExtraPercentage(mContext)));
+        assertThat(mDockDefenderTipActive.getTitle(mContext).toString()).isEqualTo(
+                mContext.getString(R.string.battery_tip_dock_defender_active_title));
+        assertThat(mDockDefenderTipTemporarilyBypassed.getTitle(mContext).toString()).isEqualTo(
+                mContext.getString(R.string.battery_tip_dock_defender_temporarily_bypassed_title));
+        assertThat(mDockDefenderTipDisabled.getTitle(mContext)).isNull();
+    }
+
+    @Test
+    public void testGetSummary() {
+        assertThat(mDockDefenderTipFutureBypass.getSummary(mContext).toString()).isEqualTo(
+                mContext.getString(R.string.battery_tip_dock_defender_future_bypass_summary,
+                        getExtraPercentage(mContext)));
+        assertThat(mDockDefenderTipActive.getSummary(mContext).toString()).isEqualTo(
+                mContext.getString(R.string.battery_tip_dock_defender_active_summary,
+                        getExtraPercentage(mContext)));
+        assertThat(mDockDefenderTipTemporarilyBypassed.getSummary(mContext).toString()).isEqualTo(
+                mContext.getString(R.string.battery_tip_dock_defender_temporarily_bypassed_summary,
+                        getExtraPercentage(mContext)));
+        assertThat(mDockDefenderTipDisabled.getSummary(mContext)).isNull();
+    }
+
+    @Test
+    public void testGetIconId() {
+        assertThat(mDockDefenderTipFutureBypass.getIconId()).isEqualTo(
+                R.drawable.ic_battery_status_protected_24dp);
+    }
+
+    @Test
+    public void testUpdateState() {
+        mDockDefenderTipTemporarilyBypassed.updateState(mDockDefenderTipDisabled);
+
+        assertThat(mDockDefenderTipTemporarilyBypassed.getState()).isEqualTo(
+                BatteryTip.StateType.INVISIBLE);
+        assertThat(mDockDefenderTipTemporarilyBypassed.getMode()).isEqualTo(
+                BatteryUtils.DockDefenderMode.DISABLED);
+    }
+
+    @Test
+    public void testLog() {
+        mDockDefenderTipActive.log(mContext, mMetricsFeatureProvider);
+
+        verify(mMetricsFeatureProvider).action(mContext, SettingsEnums.ACTION_DOCK_DEFENDER_TIP,
+                mDockDefenderTipActive.getState());
+    }
+
+
+    @Test
+    public void testUpdatePreference_dockDefenderTipFutureBypass() {
+        mDockDefenderTipFutureBypass.updatePreference(mCardPreference);
+
+        verify(mCardPreference).setPrimaryButtonVisible(true);
+        verify(mCardPreference).setPrimaryButtonText(
+                mContext.getString(R.string.battery_tip_charge_to_full_button));
+        verifySecondaryButton();
+    }
+
+    @Test
+    public void testUpdatePreference_dockDefenderTipActive() {
+        mDockDefenderTipActive.updatePreference(mCardPreference);
+
+        verify(mCardPreference).setPrimaryButtonVisible(true);
+        verify(mCardPreference).setPrimaryButtonText(
+                mContext.getString(R.string.battery_tip_charge_to_full_button));
+        verifySecondaryButton();
+    }
+
+    @Test
+    public void testUpdatePreference_dockDefenderTipTemporarilyBypassed() {
+        mDockDefenderTipTemporarilyBypassed.updatePreference(mCardPreference);
+
+        verify(mCardPreference).setPrimaryButtonVisible(false);
+        verify(mCardPreference, never()).setPrimaryButtonText(any());
+        verifySecondaryButton();
+    }
+
+    private void verifySecondaryButton() {
+        verify(mCardPreference).setSecondaryButtonText(mContext.getString(R.string.learn_more));
+        verify(mCardPreference).setSecondaryButtonVisible(true);
+        verify(mCardPreference).setSecondaryButtonContentDescription(mContext.getString(
+                R.string.battery_tip_limited_temporarily_sec_button_content_description));
+    }
+
+    @Test
+    public void updatePreference_castFail_logErrorMessage() {
+        mDockDefenderTipActive.updatePreference(mPreference);
+
+        assertThat(getLastErrorLog()).isEqualTo("cast Preference to CardPreference failed");
+    }
+
+    private String getLastErrorLog() {
+        return ShadowLog.getLogsForTag(DockDefenderTip.class.getSimpleName()).stream().filter(
+                log -> log.type == Log.ERROR).reduce((first, second) -> second).orElse(
+                createErrorLog("No Error Log")).msg;
+    }
+
+    private ShadowLog.LogItem createErrorLog(String msg) {
+        return new ShadowLog.LogItem(Log.ERROR, "tag", msg, null);
+    }
+
+    private String getExtraPercentage(Context context) {
+        final int extraValue = context.getResources().getInteger(
+                R.integer.config_battery_extra_tip_value);
+        return NumberFormat.getPercentInstance().format(extraValue * 0.01f);
+    }
+
+}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/PowerUsageBaseTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/PowerUsageBaseTest.java
index 2700930..6ed10cd 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/PowerUsageBaseTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/PowerUsageBaseTest.java
@@ -15,18 +15,26 @@
  */
 package com.android.settings.fuelgauge.batteryusage;
 
+import static com.android.settings.fuelgauge.batteryusage.PowerUsageBase.KEY_INCLUDE_HISTORY;
+import static com.android.settings.fuelgauge.batteryusage.PowerUsageBase.KEY_REFRESH_TYPE;
+
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.refEq;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
 
 import android.content.Context;
+import android.os.BatteryUsageStats;
 import android.os.Bundle;
 
 import androidx.loader.app.LoaderManager;
+import androidx.loader.content.Loader;
 
+import com.android.settings.fuelgauge.BatteryBroadcastReceiver;
 import com.android.settings.testutils.shadow.ShadowDashboardFragment;
 import com.android.settingslib.core.AbstractPreferenceController;
 
@@ -46,14 +54,15 @@
 
     @Mock
     private LoaderManager mLoaderManager;
+    @Mock
+    private Loader<BatteryUsageStats> mBatteryUsageStatsLoader;
     private TestFragment mFragment;
 
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
 
-        mFragment = spy(new TestFragment());
-        doReturn(mLoaderManager).when(mFragment).getLoaderManager();
+        mFragment = spy(new TestFragment(mLoaderManager));
     }
 
     @Test
@@ -63,7 +72,62 @@
         verify(mLoaderManager, never()).initLoader(anyInt(), any(Bundle.class), any());
     }
 
-    public static class TestFragment extends PowerUsageBase {
+    @Test
+    public void restartBatteryInfoLoader() {
+        final Bundle bundle = new Bundle();
+        bundle.putInt(KEY_REFRESH_TYPE, BatteryBroadcastReceiver.BatteryUpdateType.BATTERY_STATUS);
+        bundle.putBoolean(KEY_INCLUDE_HISTORY, false);
+        doReturn(mBatteryUsageStatsLoader).when(mLoaderManager).getLoader(
+                PowerUsageBase.LoaderIndex.BATTERY_USAGE_STATS_LOADER);
+        doReturn(false).when(mBatteryUsageStatsLoader).isReset();
+
+        mFragment.restartBatteryStatsLoader(
+                BatteryBroadcastReceiver.BatteryUpdateType.BATTERY_STATUS);
+
+        verify(mLoaderManager)
+                .restartLoader(eq(PowerUsageBase.LoaderIndex.BATTERY_USAGE_STATS_LOADER),
+                        refEq(bundle), any());
+    }
+
+    @Test
+    public void restartBatteryInfoLoader_loaderReset_initLoader() {
+        final Bundle bundle = new Bundle();
+        bundle.putInt(KEY_REFRESH_TYPE, BatteryBroadcastReceiver.BatteryUpdateType.BATTERY_STATUS);
+        bundle.putBoolean(KEY_INCLUDE_HISTORY, false);
+        doReturn(mBatteryUsageStatsLoader).when(mLoaderManager).getLoader(
+                PowerUsageBase.LoaderIndex.BATTERY_USAGE_STATS_LOADER);
+        doReturn(true).when(mBatteryUsageStatsLoader).isReset();
+
+        mFragment.restartBatteryStatsLoader(
+                BatteryBroadcastReceiver.BatteryUpdateType.BATTERY_STATUS);
+
+        verify(mLoaderManager)
+                .initLoader(eq(PowerUsageBase.LoaderIndex.BATTERY_USAGE_STATS_LOADER),
+                        refEq(bundle), any());
+    }
+
+    @Test
+    public void restartBatteryInfoLoader_nullLoader_initLoader() {
+        final Bundle bundle = new Bundle();
+        bundle.putInt(KEY_REFRESH_TYPE, BatteryBroadcastReceiver.BatteryUpdateType.BATTERY_STATUS);
+        bundle.putBoolean(KEY_INCLUDE_HISTORY, false);
+        doReturn(null).when(mLoaderManager).getLoader(
+                PowerUsageBase.LoaderIndex.BATTERY_USAGE_STATS_LOADER);
+
+        mFragment.restartBatteryStatsLoader(
+                BatteryBroadcastReceiver.BatteryUpdateType.BATTERY_STATUS);
+
+        verify(mLoaderManager).initLoader(eq(PowerUsageBase.LoaderIndex.BATTERY_USAGE_STATS_LOADER),
+                refEq(bundle), any());
+    }
+
+    private static class TestFragment extends PowerUsageBase {
+
+        private LoaderManager mLoaderManager;
+
+        TestFragment(LoaderManager loaderManager) {
+            mLoaderManager = loaderManager;
+        }
 
         @Override
         public int getMetricsCategory() {
@@ -94,5 +158,10 @@
         protected List<AbstractPreferenceController> createPreferenceControllers(Context context) {
             return null;
         }
+
+        @Override
+        protected LoaderManager getLoaderManagerForCurrentFragment() {
+            return mLoaderManager;
+        }
     }
 }
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/PowerUsageSummaryTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/PowerUsageSummaryTest.java
index fa049f8..04bf019 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/PowerUsageSummaryTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/PowerUsageSummaryTest.java
@@ -15,7 +15,6 @@
  */
 package com.android.settings.fuelgauge.batteryusage;
 
-import static com.android.settings.fuelgauge.batteryusage.PowerUsageSummary.BATTERY_INFO_LOADER;
 import static com.android.settings.fuelgauge.batteryusage.PowerUsageSummary.KEY_BATTERY_ERROR;
 import static com.android.settings.fuelgauge.batteryusage.PowerUsageSummary.KEY_BATTERY_USAGE;
 
@@ -39,14 +38,17 @@
 import android.provider.Settings;
 
 import androidx.loader.app.LoaderManager;
+import androidx.loader.content.Loader;
 import androidx.preference.Preference;
 import androidx.preference.PreferenceScreen;
 
 import com.android.settings.R;
 import com.android.settings.SettingsActivity;
 import com.android.settings.fuelgauge.BatteryBroadcastReceiver;
+import com.android.settings.fuelgauge.BatteryInfo;
 import com.android.settings.fuelgauge.BatteryUtils;
 import com.android.settings.fuelgauge.batterytip.BatteryTipPreferenceController;
+import com.android.settings.fuelgauge.batterytip.tips.BatteryTip;
 import com.android.settings.testutils.FakeFeatureFactory;
 import com.android.settings.testutils.XmlTestUtils;
 import com.android.settings.testutils.shadow.ShadowUtils;
@@ -69,8 +71,6 @@
 // TODO: Improve this test class so that it starts up the real activity and fragment.
 @RunWith(RobolectricTestRunner.class)
 public class PowerUsageSummaryTest {
-
-    private static final long TIME_SINCE_LAST_FULL_CHARGE_MS = 120 * 60 * 1000;
     private static Intent sAdditionalBatteryInfoIntent;
 
     @BeforeClass
@@ -83,6 +83,10 @@
     @Mock
     private LoaderManager mLoaderManager;
     @Mock
+    private Loader<BatteryTip> mBatteryTipLoader;
+    @Mock
+    private Loader<BatteryInfo> mBatteryInfoLoader;
+    @Mock
     private ContentResolver mContentResolver;
     @Mock
     private BatteryBroadcastReceiver mBatteryBroadcastReceiver;
@@ -105,11 +109,9 @@
 
         mRealContext = spy(RuntimeEnvironment.application);
         mFeatureFactory = FakeFeatureFactory.setupForTest();
-        mFragment = spy(new TestFragment(mRealContext));
+        mFragment = spy(new TestFragment(mRealContext, mLoaderManager));
         mFragment.initFeatureProvider();
         doNothing().when(mFragment).restartBatteryStatsLoader(anyInt());
-        doReturn(mock(LoaderManager.class)).when(mFragment).getLoaderManager();
-
         when(mFragment.getActivity()).thenReturn(mSettingsActivity);
         when(mFeatureFactory.powerUsageFeatureProvider.getAdditionalBatteryInfoIntent())
                 .thenReturn(sAdditionalBatteryInfoIntent);
@@ -155,12 +157,58 @@
     @Test
     public void restartBatteryTipLoader() {
         //TODO: add policy logic here when BatteryTipPolicy is implemented
-        doReturn(mLoaderManager).when(mFragment).getLoaderManager();
+        doReturn(mBatteryTipLoader).when(mLoaderManager).getLoader(
+                PowerUsageBase.LoaderIndex.BATTERY_TIP_LOADER);
+        doReturn(false).when(mBatteryTipLoader).isReset();
 
         mFragment.restartBatteryTipLoader();
 
-        verify(mLoaderManager)
-                .restartLoader(eq(PowerUsageSummary.BATTERY_TIP_LOADER), eq(Bundle.EMPTY), any());
+        verify(mLoaderManager).restartLoader(eq(PowerUsageBase.LoaderIndex.BATTERY_TIP_LOADER),
+                eq(Bundle.EMPTY), any());
+    }
+
+    @Test
+    public void restartBatteryTipLoader_nullLoader_initLoader() {
+        doReturn(null).when(mLoaderManager).getLoader(
+                PowerUsageBase.LoaderIndex.BATTERY_TIP_LOADER);
+
+        mFragment.restartBatteryTipLoader();
+
+        verify(mLoaderManager).initLoader(eq(PowerUsageBase.LoaderIndex.BATTERY_TIP_LOADER),
+                eq(Bundle.EMPTY), any());
+    }
+
+    @Test
+    public void restartBatteryTipLoader_loaderReset_initLoader() {
+        doReturn(mBatteryTipLoader).when(mLoaderManager).getLoader(
+                PowerUsageBase.LoaderIndex.BATTERY_TIP_LOADER);
+        doReturn(true).when(mBatteryTipLoader).isReset();
+
+        mFragment.restartBatteryTipLoader();
+
+
+        verify(mLoaderManager).initLoader(eq(PowerUsageBase.LoaderIndex.BATTERY_TIP_LOADER),
+                eq(Bundle.EMPTY), any());
+    }
+
+
+    @Test
+    public void refreshUi_contextNull_doNothing() {
+        doReturn(null).when(mFragment).getContext();
+
+        mFragment.refreshUi(BatteryBroadcastReceiver.BatteryUpdateType.MANUAL);
+
+        verify(mFragment, never()).restartBatteryTipLoader();
+        verify(mFragment, never()).restartBatteryInfoLoader();
+    }
+
+    @Test
+    public void refreshUi_batteryNotPresent_doNothing() {
+        mFragment.setIsBatteryPresent(false);
+        mFragment.refreshUi(BatteryBroadcastReceiver.BatteryUpdateType.MANUAL);
+
+        verify(mFragment, never()).restartBatteryTipLoader();
+        verify(mFragment, never()).restartBatteryInfoLoader();
     }
 
     @Test
@@ -168,10 +216,12 @@
         mFragment.mBatteryTipPreferenceController = mock(BatteryTipPreferenceController.class);
         when(mFragment.mBatteryTipPreferenceController.needUpdate()).thenReturn(false);
         mFragment.updateBatteryTipFlag(new Bundle());
+        doNothing().when(mFragment).restartBatteryInfoLoader();
 
         mFragment.refreshUi(BatteryBroadcastReceiver.BatteryUpdateType.MANUAL);
 
         verify(mFragment, never()).restartBatteryTipLoader();
+        verify(mFragment).restartBatteryInfoLoader();
     }
 
     @Test
@@ -179,10 +229,12 @@
         mFragment.mBatteryTipPreferenceController = mock(BatteryTipPreferenceController.class);
         when(mFragment.mBatteryTipPreferenceController.needUpdate()).thenReturn(true);
         mFragment.updateBatteryTipFlag(new Bundle());
+        doNothing().when(mFragment).restartBatteryInfoLoader();
 
         mFragment.refreshUi(BatteryBroadcastReceiver.BatteryUpdateType.BATTERY_LEVEL);
 
         verify(mFragment, never()).restartBatteryTipLoader();
+        verify(mFragment).restartBatteryInfoLoader();
     }
 
     @Test
@@ -190,10 +242,13 @@
         mFragment.mBatteryTipPreferenceController = mock(BatteryTipPreferenceController.class);
         when(mFragment.mBatteryTipPreferenceController.needUpdate()).thenReturn(true);
         mFragment.updateBatteryTipFlag(new Bundle());
+        doNothing().when(mFragment).restartBatteryInfoLoader();
+        doNothing().when(mFragment).restartBatteryTipLoader();
 
         mFragment.refreshUi(BatteryBroadcastReceiver.BatteryUpdateType.MANUAL);
 
         verify(mFragment).restartBatteryTipLoader();
+        verify(mFragment).restartBatteryInfoLoader();
     }
 
     @Test
@@ -217,19 +272,68 @@
     @Test
     public void restartBatteryInfoLoader_contextNull_doNothing() {
         when(mFragment.getContext()).thenReturn(null);
-        when(mFragment.getLoaderManager()).thenReturn(mLoaderManager);
 
         mFragment.restartBatteryInfoLoader();
 
-        verify(mLoaderManager, never()).restartLoader(BATTERY_INFO_LOADER, Bundle.EMPTY,
+        verify(mLoaderManager, never()).restartLoader(
+                PowerUsageBase.LoaderIndex.BATTERY_INFO_LOADER, Bundle.EMPTY,
                 mFragment.mBatteryInfoLoaderCallbacks);
     }
 
-    public static class TestFragment extends PowerUsageSummary {
-        private Context mContext;
+    @Test
+    public void restartBatteryInfoLoader_batteryIsNotPresent_doNothing() {
+        mFragment.setIsBatteryPresent(false);
 
-        public TestFragment(Context context) {
+        mFragment.restartBatteryInfoLoader();
+
+        verify(mLoaderManager, never()).restartLoader(
+                PowerUsageBase.LoaderIndex.BATTERY_INFO_LOADER, Bundle.EMPTY,
+                mFragment.mBatteryInfoLoaderCallbacks);
+    }
+
+    @Test
+    public void restartBatteryInfoLoader() {
+        doReturn(mBatteryInfoLoader).when(mLoaderManager).getLoader(
+                PowerUsageBase.LoaderIndex.BATTERY_INFO_LOADER);
+        doReturn(false).when(mBatteryTipLoader).isReset();
+
+        mFragment.restartBatteryInfoLoader();
+
+        verify(mLoaderManager).restartLoader(eq(PowerUsageBase.LoaderIndex.BATTERY_INFO_LOADER),
+                eq(Bundle.EMPTY), any());
+    }
+
+    @Test
+    public void restartBatteryInfoLoader_nullLoader_initLoader() {
+        doReturn(null).when(mLoaderManager).getLoader(
+                PowerUsageBase.LoaderIndex.BATTERY_INFO_LOADER);
+
+        mFragment.restartBatteryInfoLoader();
+
+        verify(mLoaderManager).initLoader(eq(PowerUsageBase.LoaderIndex.BATTERY_INFO_LOADER),
+                eq(Bundle.EMPTY), any());
+    }
+
+    @Test
+    public void restartBatteryInfoLoader_loaderReset_initLoader() {
+        mFragment.setIsBatteryPresent(true);
+        doReturn(mBatteryInfoLoader).when(mLoaderManager).getLoader(
+                PowerUsageBase.LoaderIndex.BATTERY_INFO_LOADER);
+        doReturn(true).when(mBatteryInfoLoader).isReset();
+
+        mFragment.restartBatteryInfoLoader();
+
+        verify(mLoaderManager).initLoader(eq(PowerUsageBase.LoaderIndex.BATTERY_INFO_LOADER),
+                eq(Bundle.EMPTY), any());
+    }
+
+    private static class TestFragment extends PowerUsageSummary {
+        private Context mContext;
+        private LoaderManager mLoaderManager;
+
+        TestFragment(Context context, LoaderManager loaderManager) {
             mContext = context;
+            mLoaderManager = loaderManager;
         }
 
         @Override
@@ -242,5 +346,15 @@
             // Override it so we can access this method in test
             return super.getContentResolver();
         }
+
+        public void setIsBatteryPresent(boolean isBatteryPresent) {
+            mIsBatteryPresent = isBatteryPresent;
+        }
+
+        @Override
+        protected LoaderManager getLoaderManagerForCurrentFragment() {
+            return mLoaderManager;
+        }
     }
+
 }
diff --git a/tests/robotests/src/com/android/settings/homepage/SettingsHomepageActivityTest.java b/tests/robotests/src/com/android/settings/homepage/SettingsHomepageActivityTest.java
index 7387407..337b659 100644
--- a/tests/robotests/src/com/android/settings/homepage/SettingsHomepageActivityTest.java
+++ b/tests/robotests/src/com/android/settings/homepage/SettingsHomepageActivityTest.java
@@ -20,6 +20,8 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
@@ -40,9 +42,11 @@
 import com.android.settings.R;
 import com.android.settings.dashboard.suggestions.SuggestionFeatureProviderImpl;
 import com.android.settings.testutils.shadow.ShadowActivityEmbeddingUtils;
+import com.android.settings.testutils.shadow.ShadowPasswordUtils;
 import com.android.settings.testutils.shadow.ShadowUserManager;
 import com.android.settingslib.core.lifecycle.HideNonSystemOverlayMixin;
 
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -69,6 +73,11 @@
         MockitoAnnotations.initMocks(this);
     }
 
+    @After
+    public void tearDown() {
+        ShadowPasswordUtils.reset();
+    }
+
     @Test
     public void launch_shouldHaveAnimationForIaFragment() {
         final SettingsHomepageActivity activity = Robolectric.buildActivity(
@@ -208,6 +217,32 @@
         verify(activity).initSplitPairRules();
     }
 
+    @Test
+    @Config(shadows = {ShadowPasswordUtils.class})
+    public void isCallingAppPermitted_emptyPermission_returnTrue() {
+        SettingsHomepageActivity homepageActivity = spy(new SettingsHomepageActivity());
+
+        assertTrue(homepageActivity.isCallingAppPermitted(""));
+    }
+
+    @Test
+    @Config(shadows = {ShadowPasswordUtils.class})
+    public void isCallingAppPermitted_noGrantedPermission_returnFalse() {
+        SettingsHomepageActivity homepageActivity = spy(new SettingsHomepageActivity());
+
+        assertFalse(homepageActivity.isCallingAppPermitted("android.permission.TEST"));
+    }
+
+    @Test
+    @Config(shadows = {ShadowPasswordUtils.class})
+    public void isCallingAppPermitted_grantedPermission_returnTrue() {
+        SettingsHomepageActivity homepageActivity = spy(new SettingsHomepageActivity());
+        String permission = "android.permission.TEST";
+        ShadowPasswordUtils.addGrantedPermission(permission);
+
+        assertTrue(homepageActivity.isCallingAppPermitted(permission));
+    }
+
     @Implements(SuggestionFeatureProviderImpl.class)
     public static class ShadowSuggestionFeatureProviderImpl {
 
diff --git a/tests/robotests/src/com/android/settings/testutils/BatteryTestUtils.java b/tests/robotests/src/com/android/settings/testutils/BatteryTestUtils.java
index e4e26d2..a6f2430 100644
--- a/tests/robotests/src/com/android/settings/testutils/BatteryTestUtils.java
+++ b/tests/robotests/src/com/android/settings/testutils/BatteryTestUtils.java
@@ -37,7 +37,7 @@
                 BatteryManager.BATTERY_STATUS_DISCHARGING);
     }
 
-    private static Intent getCustomBatteryIntent(int plugged, int level, int scale, int status) {
+    public static Intent getCustomBatteryIntent(int plugged, int level, int scale, int status) {
         Intent intent = new Intent();
         intent.putExtra(BatteryManager.EXTRA_PLUGGED, plugged);
         intent.putExtra(BatteryManager.EXTRA_LEVEL, level);
diff --git a/tests/unit/src/com/android/settings/biometrics/fingerprint/FingerprintStatusUtilsTest.java b/tests/unit/src/com/android/settings/biometrics/fingerprint/FingerprintStatusUtilsTest.java
index a5d74a0..69e5e2f 100644
--- a/tests/unit/src/com/android/settings/biometrics/fingerprint/FingerprintStatusUtilsTest.java
+++ b/tests/unit/src/com/android/settings/biometrics/fingerprint/FingerprintStatusUtilsTest.java
@@ -179,20 +179,8 @@
     }
 
     @Test
-    public void getSettingsClassName_whenNotEnrolled_fingerprintOnly_returnsFingerprintEnrollInduction() {
+    public void getSettingsClassName_whenNotEnrolled_returnsFingerprintSettings() {
         when(mFingerprintManager.hasEnrolledFingerprints(anyInt())).thenReturn(false);
-        when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
-        when(mFaceManager.isHardwareDetected()).thenReturn(false);
-
-        assertThat(mFingerprintStatusUtils.getSettingsClassName())
-                .isEqualTo(FingerprintEnrollIntroductionInternal.class.getName());
-    }
-
-    @Test
-    public void getSettingsClassName_whenNotEnrolled_fingerprintNotOnly_returnsFingerprintSettings() {
-        when(mFingerprintManager.hasEnrolledFingerprints(anyInt())).thenReturn(false);
-        when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
-        when(mFaceManager.isHardwareDetected()).thenReturn(true);
 
         assertThat(mFingerprintStatusUtils.getSettingsClassName())
                 .isEqualTo(FingerprintSettings.class.getName());