Merge "Add OWNERS for folder bluetooth"
diff --git a/OWNERS b/OWNERS
new file mode 100644
index 0000000..e19e56f
--- /dev/null
+++ b/OWNERS
@@ -0,0 +1,15 @@
+# Use this reviewer by default.
+pixel-sw-exp-reviews+gerrit@google.com
+
+# People who can approve changes for submission
+asapperstein@google.com
+asargent@google.com
+dehboxturtle@google.com
+dhnishi@google.com
+dling@google.com
+jackqdyulei@google.com
+mfritze@google.com
+zhfan@google.com
+
+# Emergency approvers in case the above are not available
+miket@google.com
diff --git a/res/values/strings.xml b/res/values/strings.xml
index fcc0b6d..51305b5 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -3633,8 +3633,6 @@
     <string name="recent_app_category_title">Recently opened apps</string>
     <!-- Preference title for showing all apps on device [CHAR_LIMIT=50]-->
     <string name="see_all_apps_title">See all <xliff:g id="count" example="3">%1$d</xliff:g> apps</string>
-    <!-- Preference summary for each recently used app, which is the time since last used, i.e. "7 h 20 min ago". Note: ^1 should be used in all translations [CHAR_LIMIT=60] -->
-    <string name="recent_app_summary"><xliff:g id="time">^1</xliff:g> ago</string>
 
     <!-- Warning that appears below the unknown sources switch in settings -->
     <string name="install_all_warning" product="tablet">
@@ -4630,6 +4628,12 @@
     <string name="background_activity_summary_off">App\'s background activity is limited when not in use</string>
     <!-- Summary for the background activity when it is disabled [CHAR_LIMIT=120] -->
     <string name="background_activity_summary_disabled">App not allowed to run in background</string>
+    <!-- TODO: Pending UX review. Summary for the background activity when it is whitlisted [CHAR_LIMIT=120] -->
+    <string name="background_activity_summary_whitelisted">App can not be optimized for battery use</string>
+    <!-- TODO: Pending UX review. Title for the warning dialog to show to the user when limiting background activity for an app -->
+    <string name="background_activity_warning_dialog_title">Limit background activity?</string>
+    <!-- TODO: Pending UX review. Text for the warning dialog to show to the user when limiting background activity for an app -->
+    <string name="background_activity_warning_dialog_text">If you limit background activity for an app, it may misbehave</string>
 
     <!-- Title for the screen usage in power use UI [CHAR_LIMIT=60] -->
     <string name="device_screen_usage">Screen usage since full charge</string>
@@ -4638,12 +4642,10 @@
     <!-- Title for the cellular network in power use UI(i.e. Mobile network scanning: 30% of battery usage) [CHAR_LIMIT=40] -->
     <string name="device_cellular_network">Mobile network scanning</string>
 
-    <!-- Label for time since last full charge in power use UI, i.e. "7 h 20 min ago". Note: ^1 should be used in all translations [CHAR_LIMIT=60] -->
-    <string name="power_last_full_charge_summary"><xliff:g id="time">^1</xliff:g> ago</string>
     <!-- Label for list of apps using battery in power use UI. Note: ^1 should be used in all translations[CHAR_LIMIT=120] -->
-    <string name="power_usage_list_summary">App usage since full charge (<xliff:g id="time">^1</xliff:g> ago)</string>
+    <string name="power_usage_list_summary">App usage since full charge (<xliff:g id="relative_time">^1</xliff:g>)</string>
     <!-- Label for device components using battery in power use UI. Note: ^1 should be used in all translations[CHAR_LIMIT=120] -->
-    <string name="power_usage_list_summary_device">Device usage since full charge (<xliff:g id="time">^1</xliff:g> ago)</string>
+    <string name="power_usage_list_summary_device">Device usage since full charge (<xliff:g id="relative_time">^1</xliff:g>)</string>
     <!-- Description for the screen usage item [CHAR_LIMIT=120] -->
     <string name="screen_usage_summary">Amount of time screen has been on since full charge</string>
     <!-- Label for list of different types using battery in power use UI [CHAR_LIMIT=60] -->
diff --git a/res/xml/wifi_network_details_fragment.xml b/res/xml/wifi_network_details_fragment.xml
index 550ab36..5407947 100644
--- a/res/xml/wifi_network_details_fragment.xml
+++ b/res/xml/wifi_network_details_fragment.xml
@@ -22,14 +22,14 @@
         android:selectable="false"
         android:order="-10000"/>
 
+    <!-- Buttons -->
+    <com.android.settings.widget.ActionButtonPreference
+        android:key="buttons"
+        android:selectable="false" />
+
     <!-- General Details Category -->
     <PreferenceCategory
             android:key="general_details_category" >
-        <!-- Buttons -->
-        <com.android.settings.widget.ActionButtonPreference
-            android:key="buttons"
-            android:selectable="false" />
-
         <com.android.settings.wifi.WifiDetailPreference
                 android:key="signal_strength"
                 android:title="@string/wifi_signal"
@@ -87,5 +87,4 @@
                 android:key="ipv6_addresses"
                 android:selectable="false"/>
     </PreferenceCategory>
-
 </PreferenceScreen>
diff --git a/src/com/android/settings/Utils.java b/src/com/android/settings/Utils.java
index 417ac0f..fa61cec 100644
--- a/src/com/android/settings/Utils.java
+++ b/src/com/android/settings/Utils.java
@@ -52,8 +52,11 @@
 import android.graphics.BitmapFactory;
 import android.hardware.fingerprint.FingerprintManager;
 import android.icu.text.MeasureFormat;
+import android.icu.text.RelativeDateTimeFormatter;
+import android.icu.text.RelativeDateTimeFormatter.RelativeUnit;
 import android.icu.util.Measure;
 import android.icu.util.MeasureUnit;
+import android.icu.util.ULocale;
 import android.net.ConnectivityManager;
 import android.net.LinkProperties;
 import android.net.Network;
@@ -861,6 +864,48 @@
     }
 
     /**
+     * Returns relative time for the given millis in the past, in a short format such as "2 days
+     * ago", "5 hr. ago", "40 min. ago", or "29 sec. ago".
+     *
+     * <p>The unit is chosen to have good information value while only using one unit. So 27 hours
+     * and 50 minutes would be formatted as "28 hr. ago", while 50 hours would be formatted as
+     * "2 days ago".
+     *
+     * @param context the application context
+     * @param millis the elapsed time in milli seconds
+     * @param withSeconds include seconds?
+     * @return the formatted elapsed time
+     */
+    public static CharSequence formatRelativeTime(Context context, double millis,
+            boolean withSeconds) {
+        final int seconds = (int) Math.floor(millis / 1000);
+        final RelativeUnit unit;
+        final int value;
+        if (withSeconds && seconds < 2 * SECONDS_PER_MINUTE) {
+            unit = RelativeUnit.SECONDS;
+            value = seconds;
+        } else if (seconds < 2 * SECONDS_PER_HOUR) {
+            unit = RelativeUnit.MINUTES;
+            value = (seconds + SECONDS_PER_MINUTE / 2) / SECONDS_PER_MINUTE;
+        } else if (seconds < 2 * SECONDS_PER_DAY) {
+            unit = RelativeUnit.HOURS;
+            value = (seconds + SECONDS_PER_HOUR / 2) / SECONDS_PER_HOUR;
+        } else {
+            unit = RelativeUnit.DAYS;
+            value = (seconds + SECONDS_PER_DAY / 2) / SECONDS_PER_DAY;
+        }
+
+        final Locale locale = context.getResources().getConfiguration().locale;
+        final RelativeDateTimeFormatter formatter = RelativeDateTimeFormatter.getInstance(
+                ULocale.forLocale(locale),
+                null /* default NumberFormat */,
+                RelativeDateTimeFormatter.Style.SHORT,
+                android.icu.text.DisplayContext.CAPITALIZATION_FOR_MIDDLE_OF_SENTENCE);
+
+        return formatter.format(value, RelativeDateTimeFormatter.Direction.LAST, unit);
+    }
+
+    /**
      * Queries for the UserInfo of a user. Returns null if the user doesn't exist (was removed).
      * @param userManager Instance of UserManager
      * @param checkUser The user to check the existence of.
diff --git a/src/com/android/settings/accessibility/OWNERS b/src/com/android/settings/accessibility/OWNERS
new file mode 100644
index 0000000..28dfdef
--- /dev/null
+++ b/src/com/android/settings/accessibility/OWNERS
@@ -0,0 +1,3 @@
+# Default reviewers for this and subdirectories.
+pweaver@google.com
+zork@google.com
\ No newline at end of file
diff --git a/src/com/android/settings/applications/RecentAppsPreferenceController.java b/src/com/android/settings/applications/RecentAppsPreferenceController.java
index d0f7584..69a36f67 100644
--- a/src/com/android/settings/applications/RecentAppsPreferenceController.java
+++ b/src/com/android/settings/applications/RecentAppsPreferenceController.java
@@ -235,10 +235,8 @@
             pref.setKey(pkgName);
             pref.setTitle(appEntry.label);
             pref.setIcon(mIconDrawableFactory.getBadgedIcon(appEntry.info));
-            pref.setSummary(TextUtils.expandTemplate(
-                mContext.getResources().getText(R.string.recent_app_summary),
-                Utils.formatElapsedTime(mContext,
-                    System.currentTimeMillis() - stat.getLastTimeUsed(), false)));
+            pref.setSummary(Utils.formatRelativeTime(mContext,
+                    System.currentTimeMillis() - stat.getLastTimeUsed(), false));
             pref.setOrder(i);
             pref.setOnPreferenceClickListener(preference -> {
                 AppInfoBase.startAppInfoFragment(InstalledAppDetails.class,
diff --git a/src/com/android/settings/backup/OWNERS b/src/com/android/settings/backup/OWNERS
new file mode 100644
index 0000000..c026a35
--- /dev/null
+++ b/src/com/android/settings/backup/OWNERS
@@ -0,0 +1,6 @@
+# Default reviewers for this and subdirectories.
+bryanmawhinney@google.com
+cprins@google.com
+jorlow@google.com
+philippov@google.com
+stefanot@google.com
\ No newline at end of file
diff --git a/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java b/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java
index 30be654..919dc3a 100644
--- a/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java
+++ b/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java
@@ -17,12 +17,16 @@
 package com.android.settings.development;
 
 import android.content.Context;
+import android.os.Bundle;
 import android.os.UserManager;
 import android.provider.SearchIndexableResource;
 import android.util.Log;
+import android.widget.Switch;
 
 import com.android.internal.logging.nano.MetricsProto;
 import com.android.settings.R;
+import com.android.settings.SettingsActivity;
+import com.android.settings.Utils;
 import com.android.settings.dashboard.RestrictedDashboardFragment;
 import com.android.settings.search.BaseSearchIndexProvider;
 import com.android.settings.search.Indexable;
@@ -33,22 +37,68 @@
 import java.util.Arrays;
 import java.util.List;
 
-public class DevelopmentSettingsDashboardFragment extends RestrictedDashboardFragment {
+public class DevelopmentSettingsDashboardFragment extends RestrictedDashboardFragment
+        implements SwitchBar.OnSwitchChangeListener {
 
     private static final String TAG = "DevSettingsDashboard";
 
+    private boolean mIsAvailable = true;
     private SwitchBar mSwitchBar;
+    private DevelopmentSwitchBarController mSwitchBarController;
 
     public DevelopmentSettingsDashboardFragment() {
         super(UserManager.DISALLOW_DEBUGGING_FEATURES);
     }
 
     @Override
+    public void onActivityCreated(Bundle icicle) {
+        super.onActivityCreated(icicle);
+        // Apply page-level restrictions
+        setIfOnlyAvailableForAdmins(true);
+        if (isUiRestricted() || !Utils.isDeviceProvisioned(getActivity())) {
+            // Block access to developer options if the user is not the owner, if user policy
+            // restricts it, or if the device has not been provisioned
+            mIsAvailable = false;
+            // Show error message
+            if (!isUiRestrictedByOnlyAdmin()) {
+                getEmptyTextView().setText(R.string.development_settings_not_available);
+            }
+            getPreferenceScreen().removeAll();
+            return;
+        }
+        // Set up master switch
+        mSwitchBar = ((SettingsActivity) getActivity()).getSwitchBar();
+        mSwitchBarController = new DevelopmentSwitchBarController(
+                this /* DevelopmentSettings */, mSwitchBar, mIsAvailable, getLifecycle());
+        mSwitchBar.show();
+    }
+
+    @Override
     public int getMetricsCategory() {
         return MetricsProto.MetricsEvent.DEVELOPMENT;
     }
 
     @Override
+    public void onSwitchChanged(Switch switchView, boolean isChecked) {
+        if (switchView != mSwitchBar.getSwitch()) {
+            return;
+        }
+        final boolean developmentEnabledState =
+                DevelopmentSettingsEnabler.isDevelopmentSettingsEnabled(getContext());
+        if (isChecked != developmentEnabledState) {
+            if (isChecked) {
+                EnableDevelopmentSettingWarningDialog.show(this /* host */);
+            } else {
+                // TODO: Reset dangerous options (move logic from DevelopmentSettings).
+                // resetDangerousOptions();
+                DevelopmentSettingsEnabler.setDevelopmentSettingsEnabled(getContext(), false);
+                // TODO: Refresh all prefs' enabled state (move logic from DevelopmentSettings).
+                // setPrefsEnabledState(false);
+            }
+        }
+    }
+
+    @Override
     protected String getLogTag() {
         return TAG;
     }
@@ -69,6 +119,16 @@
         return buildPreferenceControllers(context);
     }
 
+    void onEnableDevelopmentOptionsConfirmed() {
+        DevelopmentSettingsEnabler.setDevelopmentSettingsEnabled(getContext(), true);
+        // TODO: Refresh all prefs' enabled state (move logic from DevelopmentSettings).
+    }
+
+    void onEnableDevelopmentOptionsRejected() {
+        // Reset the toggle
+        mSwitchBar.setChecked(false);
+    }
+
     private static List<AbstractPreferenceController> buildPreferenceControllers(Context context) {
         return null;
     }
diff --git a/src/com/android/settings/development/DevelopmentSwitchBarController.java b/src/com/android/settings/development/DevelopmentSwitchBarController.java
index 168f7c0..ae875b3 100644
--- a/src/com/android/settings/development/DevelopmentSwitchBarController.java
+++ b/src/com/android/settings/development/DevelopmentSwitchBarController.java
@@ -22,18 +22,39 @@
 import com.android.settingslib.core.lifecycle.LifecycleObserver;
 import com.android.settingslib.core.lifecycle.events.OnStart;
 import com.android.settingslib.core.lifecycle.events.OnStop;
+import com.android.settingslib.development.DevelopmentSettingsEnabler;
 
 public class DevelopmentSwitchBarController implements LifecycleObserver, OnStart, OnStop {
 
     private final SwitchBar mSwitchBar;
     private final boolean mIsAvailable;
     private final DevelopmentSettings mSettings;
+    private final DevelopmentSettingsDashboardFragment mNewSettings;
 
+    /**
+     * @deprecated in favor of the other constructor.
+     */
+    @Deprecated
     public DevelopmentSwitchBarController(DevelopmentSettings settings, SwitchBar switchBar,
             boolean isAvailable, Lifecycle lifecycle) {
         mSwitchBar = switchBar;
         mIsAvailable = isAvailable && !Utils.isMonkeyRunning();
         mSettings = settings;
+        mNewSettings = null;
+
+        if (mIsAvailable) {
+            lifecycle.addObserver(this);
+        } else {
+            mSwitchBar.setEnabled(false);
+        }
+    }
+
+    public DevelopmentSwitchBarController(DevelopmentSettingsDashboardFragment settings,
+            SwitchBar switchBar, boolean isAvailable, Lifecycle lifecycle) {
+        mSwitchBar = switchBar;
+        mIsAvailable = isAvailable && !Utils.isMonkeyRunning();
+        mSettings = null;
+        mNewSettings = settings;
 
         if (mIsAvailable) {
             lifecycle.addObserver(this);
@@ -44,11 +65,24 @@
 
     @Override
     public void onStart() {
-        mSwitchBar.addOnSwitchChangeListener(mSettings);
+        if (mSettings != null) {
+            mSwitchBar.addOnSwitchChangeListener(mSettings);
+        }
+        if (mNewSettings != null) {
+            final boolean developmentEnabledState = DevelopmentSettingsEnabler
+                    .isDevelopmentSettingsEnabled(mNewSettings.getContext());
+            mSwitchBar.setChecked(developmentEnabledState);
+            mSwitchBar.addOnSwitchChangeListener(mNewSettings);
+        }
     }
 
     @Override
     public void onStop() {
-        mSwitchBar.removeOnSwitchChangeListener(mSettings);
+        if (mSettings != null) {
+            mSwitchBar.removeOnSwitchChangeListener(mSettings);
+        }
+        if (mNewSettings != null) {
+            mSwitchBar.removeOnSwitchChangeListener(mNewSettings);
+        }
     }
 }
diff --git a/src/com/android/settings/development/EnableDevelopmentSettingWarningDialog.java b/src/com/android/settings/development/EnableDevelopmentSettingWarningDialog.java
new file mode 100644
index 0000000..3c3d645
--- /dev/null
+++ b/src/com/android/settings/development/EnableDevelopmentSettingWarningDialog.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2017 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.development;
+
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.FragmentManager;
+import android.content.DialogInterface;
+import android.os.Bundle;
+
+import com.android.internal.logging.nano.MetricsProto;
+import com.android.settings.R;
+import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
+
+public class EnableDevelopmentSettingWarningDialog extends InstrumentedDialogFragment
+        implements DialogInterface.OnClickListener {
+
+    public static final String TAG = "EnableDevSettingDlg";
+
+    public static void show(
+            DevelopmentSettingsDashboardFragment host) {
+        final EnableDevelopmentSettingWarningDialog dialog =
+                new EnableDevelopmentSettingWarningDialog();
+        dialog.setTargetFragment(host, 0 /* requestCode */);
+        final FragmentManager manager = host.getActivity().getFragmentManager();
+        if (manager.findFragmentByTag(TAG) == null) {
+            dialog.show(manager, TAG);
+        }
+    }
+
+    @Override
+    public int getMetricsCategory() {
+        return MetricsProto.MetricsEvent.DIALOG_ENABLE_DEVELOPMENT_OPTIONS;
+    }
+
+    @Override
+    public Dialog onCreateDialog(Bundle savedInstanceState) {
+        return new AlertDialog.Builder(getActivity())
+                .setMessage(R.string.dev_settings_warning_message)
+                .setTitle(R.string.dev_settings_warning_title)
+                .setPositiveButton(android.R.string.yes, this)
+                .setNegativeButton(android.R.string.no, this)
+                .create();
+    }
+
+    @Override
+    public void onClick(DialogInterface dialog, int which) {
+        final DevelopmentSettingsDashboardFragment host =
+                (DevelopmentSettingsDashboardFragment) getTargetFragment();
+        if (which == DialogInterface.BUTTON_POSITIVE) {
+            host.onEnableDevelopmentOptionsConfirmed();
+        } else {
+            host.onEnableDevelopmentOptionsRejected();
+        }
+    }
+}
diff --git a/src/com/android/settings/enterprise/OWNERS b/src/com/android/settings/enterprise/OWNERS
new file mode 100644
index 0000000..bab2fe2
--- /dev/null
+++ b/src/com/android/settings/enterprise/OWNERS
@@ -0,0 +1,4 @@
+# Default reviewers for this and subdirectories.
+sandness@google.com
+
+# Emergency approvers in case the above are not available
\ No newline at end of file
diff --git a/src/com/android/settings/fingerprint/OWNERS b/src/com/android/settings/fingerprint/OWNERS
new file mode 100644
index 0000000..937b303
--- /dev/null
+++ b/src/com/android/settings/fingerprint/OWNERS
@@ -0,0 +1,5 @@
+# Default reviewers for this and subdirectories.
+jaggies@google.com
+yukl@google.com
+
+# Emergency approvers in case the above are not available
\ No newline at end of file
diff --git a/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetail.java b/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetail.java
index 0142e62..66a0ca2 100644
--- a/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetail.java
+++ b/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetail.java
@@ -68,7 +68,8 @@
 public class AdvancedPowerUsageDetail extends DashboardFragment implements
         ButtonActionDialogFragment.AppButtonsDialogListener,
         AnomalyDialogFragment.AnomalyDialogListener,
-        LoaderManager.LoaderCallbacks<List<Anomaly>> {
+        LoaderManager.LoaderCallbacks<List<Anomaly>>,
+        BackgroundActivityPreferenceController.WarningConfirmationListener {
 
     public static final String TAG = "AdvancedPowerUsageDetail";
     public static final String EXTRA_UID = "extra_uid";
@@ -109,6 +110,7 @@
     @VisibleForTesting
     AnomalySummaryPreferenceController mAnomalySummaryPreferenceController;
     private AppButtonsPreferenceController mAppButtonsPreferenceController;
+    private BackgroundActivityPreferenceController mBackgroundActivityPreferenceController;
 
     private DevicePolicyManagerWrapper mDpm;
     private UserManager mUserManager;
@@ -319,7 +321,9 @@
         final int uid = bundle.getInt(EXTRA_UID, 0);
         final String packageName = bundle.getString(EXTRA_PACKAGE_NAME);
 
-        controllers.add(new BackgroundActivityPreferenceController(context, uid));
+        mBackgroundActivityPreferenceController = new BackgroundActivityPreferenceController(
+                context, this, uid, packageName);
+        controllers.add(mBackgroundActivityPreferenceController);
         controllers.add(new BatteryOptimizationPreferenceController(
                 (SettingsActivity) getActivity(), this, packageName));
         mAppButtonsPreferenceController = new AppButtonsPreferenceController(
@@ -364,4 +368,10 @@
     public void onLoaderReset(Loader<List<Anomaly>> loader) {
 
     }
+
+    @Override
+    public void onLimitBackgroundActivity() {
+        mBackgroundActivityPreferenceController.setUnchecked(
+                findPreference(mBackgroundActivityPreferenceController.getPreferenceKey()));
+    }
 }
diff --git a/src/com/android/settings/fuelgauge/BackgroundActivityPreferenceController.java b/src/com/android/settings/fuelgauge/BackgroundActivityPreferenceController.java
index 4d1cf77..cea6d16 100644
--- a/src/com/android/settings/fuelgauge/BackgroundActivityPreferenceController.java
+++ b/src/com/android/settings/fuelgauge/BackgroundActivityPreferenceController.java
@@ -14,12 +14,17 @@
 
 package com.android.settings.fuelgauge;
 
+import android.app.AlertDialog;
 import android.app.AppOpsManager;
+import android.app.Dialog;
+import android.app.Fragment;
 import android.app.admin.DevicePolicyManager;
 import android.content.Context;
+import android.content.DialogInterface;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.os.Build;
+import android.os.Bundle;
 import android.os.UserManager;
 import android.support.annotation.VisibleForTesting;
 import android.support.v14.preference.SwitchPreference;
@@ -29,6 +34,7 @@
 import com.android.settings.R;
 import com.android.settings.Utils;
 import com.android.settings.core.PreferenceControllerMixin;
+import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
 import com.android.settings.enterprise.DevicePolicyManagerWrapper;
 import com.android.settings.enterprise.DevicePolicyManagerWrapperImpl;
 import com.android.settingslib.core.AbstractPreferenceController;
@@ -45,54 +51,72 @@
     private final PackageManager mPackageManager;
     private final AppOpsManager mAppOpsManager;
     private final UserManager mUserManager;
-    private final String[] mPackages;
     private final int mUid;
     @VisibleForTesting
     DevicePolicyManagerWrapper mDpm;
-
+    private Fragment mFragment;
     private String mTargetPackage;
+    private boolean mIsPreOApp;
+    private PowerWhitelistBackend mPowerWhitelistBackend;
 
-    public BackgroundActivityPreferenceController(Context context, int uid) {
+    public BackgroundActivityPreferenceController(Context context, Fragment fragment,
+            int uid, String packageName) {
+        this(context, fragment, uid, packageName, PowerWhitelistBackend.getInstance());
+    }
+
+    @VisibleForTesting
+    BackgroundActivityPreferenceController(Context context, Fragment fragment,
+            int uid, String packageName, PowerWhitelistBackend backend) {
         super(context);
+        mPowerWhitelistBackend = backend;
         mPackageManager = context.getPackageManager();
         mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
         mDpm = new DevicePolicyManagerWrapperImpl(
                 (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE));
         mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
         mUid = uid;
-        mPackages = mPackageManager.getPackagesForUid(mUid);
+        mFragment = fragment;
+        mTargetPackage = packageName;
+        mIsPreOApp = isLegacyApp(packageName);
     }
 
     @Override
     public void updateState(Preference preference) {
         final int mode = mAppOpsManager
-                .checkOpNoThrow(AppOpsManager.OP_RUN_IN_BACKGROUND, mUid, mTargetPackage);
+                .checkOpNoThrow(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, mUid, mTargetPackage);
+        final boolean whitelisted = mPowerWhitelistBackend.isWhitelisted(mTargetPackage);
         // Set checked or not before we may set it disabled
         if (mode != AppOpsManager.MODE_ERRORED) {
-            final boolean checked = mode != AppOpsManager.MODE_IGNORED;
+            final boolean checked = whitelisted || mode != AppOpsManager.MODE_IGNORED;
             ((SwitchPreference) preference).setChecked(checked);
         }
-        if (mode == AppOpsManager.MODE_ERRORED
+        if (whitelisted || mode == AppOpsManager.MODE_ERRORED
                 || Utils.isProfileOrDeviceOwner(mUserManager, mDpm, mTargetPackage)) {
             preference.setEnabled(false);
+        } else {
+            preference.setEnabled(true);
         }
-
         updateSummary(preference);
     }
 
     @Override
     public boolean isAvailable() {
-        if (mPackages == null) {
-            return false;
-        }
-        for (final String packageName : mPackages) {
-            if (isLegacyApp(packageName)) {
-                mTargetPackage = packageName;
-                return true;
-            }
-        }
+        return mTargetPackage != null;
+    }
 
-        return false;
+    /**
+     * Called from the warning dialog, if the user decides to go ahead and disable background
+     * activity for this package
+     */
+    public void setUnchecked(Preference preference) {
+        if (mIsPreOApp) {
+            mAppOpsManager.setMode(AppOpsManager.OP_RUN_IN_BACKGROUND, mUid, mTargetPackage,
+                    AppOpsManager.MODE_IGNORED);
+        }
+        mAppOpsManager.setMode(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, mUid, mTargetPackage,
+                AppOpsManager.MODE_IGNORED);
+        ((SwitchPreference) preference).setChecked(false);
+        updateSummary(preference);
     }
 
     @Override
@@ -102,20 +126,24 @@
 
     @Override
     public boolean onPreferenceChange(Preference preference, Object newValue) {
-        boolean switchOn = (Boolean) newValue;
-        mAppOpsManager.setMode(AppOpsManager.OP_RUN_IN_BACKGROUND, mUid, mTargetPackage,
-                switchOn ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_IGNORED);
-
+        final boolean switchOn = (Boolean) newValue;
+        if (!switchOn) {
+            final WarningDialogFragment dialogFragment = new WarningDialogFragment();
+            dialogFragment.setTargetFragment(mFragment, 0);
+            dialogFragment.show(mFragment.getFragmentManager(), TAG);
+            return false;
+        }
+        if (mIsPreOApp) {
+            mAppOpsManager.setMode(AppOpsManager.OP_RUN_IN_BACKGROUND, mUid, mTargetPackage,
+                    AppOpsManager.MODE_ALLOWED);
+        }
+        mAppOpsManager.setMode(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, mUid, mTargetPackage,
+                AppOpsManager.MODE_ALLOWED);
         updateSummary(preference);
         return true;
     }
 
     @VisibleForTesting
-    String getTargetPackage() {
-        return mTargetPackage;
-    }
-
-    @VisibleForTesting
     boolean isLegacyApp(final String packageName) {
         try {
             ApplicationInfo info = mPackageManager.getApplicationInfo(packageName,
@@ -131,8 +159,12 @@
 
     @VisibleForTesting
     void updateSummary(Preference preference) {
+        if (mPowerWhitelistBackend.isWhitelisted(mTargetPackage)) {
+            preference.setSummary(R.string.background_activity_summary_whitelisted);
+            return;
+        }
         final int mode = mAppOpsManager
-                .checkOpNoThrow(AppOpsManager.OP_RUN_IN_BACKGROUND, mUid, mTargetPackage);
+                .checkOpNoThrow(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, mUid, mTargetPackage);
 
         if (mode == AppOpsManager.MODE_ERRORED) {
             preference.setSummary(R.string.background_activity_summary_disabled);
@@ -142,4 +174,37 @@
                     : R.string.background_activity_summary_off);
         }
     }
+
+    interface WarningConfirmationListener {
+        void onLimitBackgroundActivity();
+    }
+
+    /**
+     * Warning dialog to show to the user as turning off background activity can lead to
+     * apps misbehaving as their background task scheduling guarantees will no longer be honored.
+     */
+    public static class WarningDialogFragment extends InstrumentedDialogFragment {
+        @Override
+        public int getMetricsCategory() {
+            // TODO (b/65494831): add metric id
+            return 0;
+        }
+
+        @Override
+        public Dialog onCreateDialog(Bundle savedInstanceState) {
+            final WarningConfirmationListener listener =
+                    (WarningConfirmationListener) getTargetFragment();
+            return new AlertDialog.Builder(getContext())
+                    .setTitle(R.string.background_activity_warning_dialog_title)
+                    .setMessage(R.string.background_activity_warning_dialog_text)
+                    .setPositiveButton(R.string.dlg_ok, new DialogInterface.OnClickListener() {
+                        @Override
+                        public void onClick(DialogInterface dialog, int which) {
+                            listener.onLimitBackgroundActivity();
+                        }
+                    })
+                    .setNegativeButton(R.string.dlg_cancel, null)
+                    .create();
+        }
+    }
 }
diff --git a/src/com/android/settings/fuelgauge/OWNERS b/src/com/android/settings/fuelgauge/OWNERS
new file mode 100644
index 0000000..5b26c46
--- /dev/null
+++ b/src/com/android/settings/fuelgauge/OWNERS
@@ -0,0 +1,6 @@
+# Default reviewers for this and subdirectories.
+dehboxturtle@google.com
+jackqdyulei@google.com
+
+# Emergency approvers in case the above are not available
+asapperstein@google.com
\ No newline at end of file
diff --git a/src/com/android/settings/fuelgauge/PowerUsageAdvanced.java b/src/com/android/settings/fuelgauge/PowerUsageAdvanced.java
index fe002b0..d29364d 100644
--- a/src/com/android/settings/fuelgauge/PowerUsageAdvanced.java
+++ b/src/com/android/settings/fuelgauge/PowerUsageAdvanced.java
@@ -124,6 +124,9 @@
         mPackageManager = context.getPackageManager();
         mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
         mBatteryUtils = BatteryUtils.getInstance(context);
+
+        // init the summary so other preferences won't have unnecessary move
+        updateHistPrefSummary(context);
     }
 
     @Override
@@ -175,7 +178,13 @@
         }
         updatePreference(mHistPref);
         refreshPowerUsageDataList(mStatsHelper, mUsageListGroup);
+        updateHistPrefSummary(context);
 
+        BatteryEntry.startRequestQueue();
+        BatteryUtils.logRuntime(TAG, "refreshUI", startTime);
+    }
+
+    private void updateHistPrefSummary(Context context) {
         Intent batteryIntent =
                 context.registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
         final boolean plugged = batteryIntent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1) != 0;
@@ -186,9 +195,6 @@
         } else {
             mHistPref.hideBottomSummary();
         }
-
-        BatteryEntry.startRequestQueue();
-        BatteryUtils.logRuntime(TAG, "refreshUI", startTime);
     }
 
     @VisibleForTesting
diff --git a/src/com/android/settings/fuelgauge/PowerUsageSummary.java b/src/com/android/settings/fuelgauge/PowerUsageSummary.java
index 1596aca..9798749 100644
--- a/src/com/android/settings/fuelgauge/PowerUsageSummary.java
+++ b/src/com/android/settings/fuelgauge/PowerUsageSummary.java
@@ -533,7 +533,7 @@
         updateScreenPreference();
         updateLastFullChargePreference(lastFullChargeTime);
 
-        final CharSequence timeSequence = Utils.formatElapsedTime(context, lastFullChargeTime,
+        final CharSequence timeSequence = Utils.formatRelativeTime(context, lastFullChargeTime,
                 false);
         final int resId = mShowAllApps ? R.string.power_usage_list_summary_device
                 : R.string.power_usage_list_summary;
@@ -682,10 +682,8 @@
 
     @VisibleForTesting
     void updateLastFullChargePreference(long timeMs) {
-        final CharSequence timeSequence = Utils.formatElapsedTime(getContext(), timeMs, false);
-        mLastFullChargePref.setSubtitle(
-                TextUtils.expandTemplate(getText(R.string.power_last_full_charge_summary),
-                        timeSequence));
+        final CharSequence timeSequence = Utils.formatRelativeTime(getContext(), timeMs, false);
+        mLastFullChargePref.setSubtitle(timeSequence);
     }
 
     @VisibleForTesting
diff --git a/src/com/android/settings/inputmethod/OWNERS b/src/com/android/settings/inputmethod/OWNERS
new file mode 100644
index 0000000..9f33394
--- /dev/null
+++ b/src/com/android/settings/inputmethod/OWNERS
@@ -0,0 +1,5 @@
+# Default reviewers for this and subdirectories.
+yukawa@google.com
+michaelwr@google.com
+
+# Emergency approvers in case the above are not available
\ No newline at end of file
diff --git a/src/com/android/settings/location/LocationSettings.java b/src/com/android/settings/location/LocationSettings.java
index 34e8cc3..d66b310 100644
--- a/src/com/android/settings/location/LocationSettings.java
+++ b/src/com/android/settings/location/LocationSettings.java
@@ -35,7 +35,6 @@
 import android.widget.Switch;
 
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import com.android.settings.DimmableIconPreference;
 import com.android.settings.R;
 import com.android.settings.SettingsActivity;
 import com.android.settings.Utils;
@@ -43,6 +42,7 @@
 import com.android.settings.dashboard.SummaryLoader;
 import com.android.settings.widget.SwitchBar;
 import com.android.settingslib.RestrictedLockUtils;
+import com.android.settingslib.RestrictedPreference;
 import com.android.settingslib.RestrictedSwitchPreference;
 import com.android.settingslib.location.RecentLocationApps;
 
@@ -207,8 +207,8 @@
 
         List<Preference> recentLocationPrefs = new ArrayList<>(recentLocationRequests.size());
         for (final RecentLocationApps.Request request : recentLocationRequests) {
-            DimmableIconPreference pref = new DimmableIconPreference(getPrefContext(),
-                    request.contentDescription);
+            RestrictedPreference pref = new RestrictedPreference(getPrefContext());
+            pref.setSummary(request.contentDescription);
             pref.setIcon(request.icon);
             pref.setTitle(request.label);
             pref.setOnPreferenceClickListener(
diff --git a/src/com/android/settings/location/OWNERS b/src/com/android/settings/location/OWNERS
new file mode 100644
index 0000000..5feda77
--- /dev/null
+++ b/src/com/android/settings/location/OWNERS
@@ -0,0 +1,10 @@
+# Default reviewers for this and subdirectories.
+asalo@google.com
+lifu@google.com
+mstogaitis@google.com
+palanki@google.com
+sooniln@google.com
+weiwa@google.com
+wyattriley@google.com
+
+# Emergency approvers in case the above are not available
\ No newline at end of file
diff --git a/src/com/android/settings/nfc/OWNERS b/src/com/android/settings/nfc/OWNERS
new file mode 100644
index 0000000..f11f74f
--- /dev/null
+++ b/src/com/android/settings/nfc/OWNERS
@@ -0,0 +1,5 @@
+# Default reviewers for this and subdirectories.
+eisenbach@google.com
+kandoiruchi@google.com
+
+# Emergency approvers in case the above are not available
\ No newline at end of file
diff --git a/src/com/android/settings/notification/OWNERS b/src/com/android/settings/notification/OWNERS
new file mode 100644
index 0000000..0d73685
--- /dev/null
+++ b/src/com/android/settings/notification/OWNERS
@@ -0,0 +1,4 @@
+# Default reviewers for this and subdirectories.
+asc@google.com
+dsandler@google.com
+juliacr@google.com
\ No newline at end of file
diff --git a/src/com/android/settings/password/OWNERS b/src/com/android/settings/password/OWNERS
new file mode 100644
index 0000000..cac6e3f
--- /dev/null
+++ b/src/com/android/settings/password/OWNERS
@@ -0,0 +1,7 @@
+# Default reviewers for this and subdirectories.
+jaggies@google.com
+kchyn@google.com
+paulcrowley@google.com
+rubinxu@google.com
+
+# Emergency approvers in case the above are not available
\ No newline at end of file
diff --git a/src/com/android/settings/tts/OWNERS b/src/com/android/settings/tts/OWNERS
new file mode 100644
index 0000000..01068dc
--- /dev/null
+++ b/src/com/android/settings/tts/OWNERS
@@ -0,0 +1,6 @@
+# Default reviewers for this and subdirectories.
+fergus@google.com
+nielse@google.com
+ssancho@google.com
+
+# Emergency approvers in case the above are not available
\ No newline at end of file
diff --git a/src/com/android/settings/users/OWNERS b/src/com/android/settings/users/OWNERS
new file mode 100644
index 0000000..59096be
--- /dev/null
+++ b/src/com/android/settings/users/OWNERS
@@ -0,0 +1,6 @@
+# Default reviewers for this and subdirectories.
+dling@google.com
+yamasani@google.com
+zhfan@google.com
+
+# Emergency approvers in case the above are not available
\ No newline at end of file
diff --git a/src/com/android/settings/wifi/OWNERS b/src/com/android/settings/wifi/OWNERS
new file mode 100644
index 0000000..3090f13
--- /dev/null
+++ b/src/com/android/settings/wifi/OWNERS
@@ -0,0 +1,9 @@
+# Default reviewers for this and subdirectories.
+asargent@google.com
+easchwar@google.com
+dling@google.com
+jlapenna@google.com
+sghuman@google.com
+zhfan@google.com
+
+# Emergency approvers in case the above are not available
\ No newline at end of file
diff --git a/src/com/android/settings/wifi/WifiConfigController.java b/src/com/android/settings/wifi/WifiConfigController.java
index 5a3d426..3cf7f93 100644
--- a/src/com/android/settings/wifi/WifiConfigController.java
+++ b/src/com/android/settings/wifi/WifiConfigController.java
@@ -492,7 +492,7 @@
         }
     }
 
-    /* package */ WifiConfiguration getConfig() {
+    public WifiConfiguration getConfig() {
         if (mMode == WifiConfigUiBase.MODE_VIEW) {
             return null;
         }
diff --git a/src/com/android/settings/wifi/WifiDialog.java b/src/com/android/settings/wifi/WifiDialog.java
index 81f2a14..cb3f8df 100644
--- a/src/com/android/settings/wifi/WifiDialog.java
+++ b/src/com/android/settings/wifi/WifiDialog.java
@@ -27,8 +27,7 @@
 import com.android.settingslib.RestrictedLockUtils;
 import com.android.settingslib.wifi.AccessPoint;
 
-// TODO(b/64069122) Have this extend a dialogfragment to handle the fullscreen launch case.
-class WifiDialog extends AlertDialog implements WifiConfigUiBase, DialogInterface.OnClickListener {
+public class WifiDialog extends AlertDialog implements WifiConfigUiBase, DialogInterface.OnClickListener {
 
     public interface WifiDialogListener {
         void onForget(WifiDialog dialog);
diff --git a/src/com/android/settings/wifi/WifiSettings.java b/src/com/android/settings/wifi/WifiSettings.java
index ef6a650..f3b08bf 100644
--- a/src/com/android/settings/wifi/WifiSettings.java
+++ b/src/com/android/settings/wifi/WifiSettings.java
@@ -884,17 +884,20 @@
      * {@link #mConnectedAccessPointPreferenceCategory}.
      */
     private void addConnectedAccessPointPreference(AccessPoint connectedAp) {
-        String key = connectedAp.getBssid();
-        LongPressAccessPointPreference pref = (LongPressAccessPointPreference)
-                getCachedPreference(key);
-        if (pref == null) {
-            pref = createLongPressActionPointPreference(connectedAp);
-        }
+        final LongPressAccessPointPreference pref = getOrCreatePreference(connectedAp);
 
         // Save the state of the current access point in the bundle so that we can restore it
         // in the Wifi Network Details Fragment
         pref.getAccessPoint().saveWifiState(pref.getExtras());
-        pref.setFragment(WifiNetworkDetailsFragment.class.getName());
+
+        // Launch details page on click.
+        pref.setOnPreferenceClickListener(preference -> {
+            SettingsActivity activity = (SettingsActivity) WifiSettings.this.getActivity();
+            activity.startPreferencePanel(this,
+                    WifiNetworkDetailsFragment.class.getName(), pref.getExtras(),
+                    R.string.wifi_details_title, null, null, 0);
+            return true;
+        });
         pref.refresh();
 
         mConnectedAccessPointPreferenceCategory.addPreference(pref);
@@ -905,6 +908,15 @@
         }
     }
 
+    private LongPressAccessPointPreference getOrCreatePreference(AccessPoint ap) {
+        LongPressAccessPointPreference pref = (LongPressAccessPointPreference)
+                getCachedPreference(AccessPointPreference.generatePreferenceKey(ap));
+        if (pref == null) {
+            pref = createLongPressActionPointPreference(ap);
+        }
+        return pref;
+    }
+
     /** Removes all preferences and hide the {@link #mConnectedAccessPointPreferenceCategory}. */
     private void removeConnectedAccessPointPreference() {
         mConnectedAccessPointPreferenceCategory.removeAll();
diff --git a/src/com/android/settings/wifi/details/WifiDetailActionBarObserver.java b/src/com/android/settings/wifi/details/WifiDetailActionBarObserver.java
deleted file mode 100644
index 81413d2..0000000
--- a/src/com/android/settings/wifi/details/WifiDetailActionBarObserver.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2017 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.wifi.details;
-
-import android.app.Fragment;
-import android.content.Context;
-import android.os.Bundle;
-import com.android.settings.R;
-import com.android.settingslib.core.lifecycle.LifecycleObserver;
-import com.android.settingslib.core.lifecycle.events.OnCreate;
-
-/**
- * ActionBar lifecycle observer for {@link WifiNetworkDetailsFragment}.
- */
-public class WifiDetailActionBarObserver implements LifecycleObserver, OnCreate {
-
-    private final Fragment mFragment;
-    private final Context mContext;
-
-    public WifiDetailActionBarObserver(Context context, Fragment fragment) {
-        mContext = context;
-        mFragment = fragment;
-    }
-
-    @Override
-    public void onCreate(Bundle savedInstanceState) {
-        if (mFragment.getActivity() != null) {
-            mFragment.getActivity().getActionBar()
-                    .setTitle(mContext.getString(R.string.wifi_details_title));
-        }
-    }
-}
diff --git a/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java b/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java
index 0996416..014fb0f 100644
--- a/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java
+++ b/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java
@@ -21,6 +21,7 @@
 
 import static com.android.settings.wifi.WifiSettings.isEditabilityLockedDown;
 
+import android.app.Activity;
 import android.app.Fragment;
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -48,7 +49,7 @@
 import android.text.TextUtils;
 import android.util.Log;
 import android.widget.ImageView;
-
+import android.widget.Toast;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.logging.nano.MetricsProto;
 import com.android.settings.R;
@@ -60,13 +61,14 @@
 import com.android.settings.widget.ActionButtonPreference;
 import com.android.settings.widget.EntityHeaderController;
 import com.android.settings.wifi.WifiDetailPreference;
+import com.android.settings.wifi.WifiDialog;
+import com.android.settings.wifi.WifiDialog.WifiDialogListener;
 import com.android.settingslib.core.AbstractPreferenceController;
 import com.android.settingslib.core.lifecycle.Lifecycle;
 import com.android.settingslib.core.lifecycle.LifecycleObserver;
 import com.android.settingslib.core.lifecycle.events.OnPause;
 import com.android.settingslib.core.lifecycle.events.OnResume;
 import com.android.settingslib.wifi.AccessPoint;
-
 import java.net.Inet4Address;
 import java.net.Inet6Address;
 import java.net.InetAddress;
@@ -79,7 +81,9 @@
  * {@link WifiNetworkDetailsFragment}.
  */
 public class WifiDetailPreferenceController extends AbstractPreferenceController
-        implements PreferenceControllerMixin, LifecycleObserver, OnPause, OnResume {
+        implements PreferenceControllerMixin, WifiDialogListener, LifecycleObserver, OnPause,
+        OnResume {
+
     private static final String TAG = "WifiDetailsPrefCtrl";
     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
 
@@ -121,7 +125,7 @@
     private NetworkCapabilities mNetworkCapabilities;
     private int mRssiSignalLevel = -1;
     private String[] mSignalStr;
-    private final WifiConfiguration mWifiConfig;
+    private WifiConfiguration mWifiConfig;
     private WifiInfo mWifiInfo;
     private final WifiManager mWifiManager;
     private final MetricsFeatureProvider mMetricsFeatureProvider;
@@ -147,9 +151,21 @@
         @Override
         public void onReceive(Context context, Intent intent) {
             switch (intent.getAction()) {
+                case WifiManager.CONFIGURED_NETWORKS_CHANGED_ACTION:
+                    if (!intent.getBooleanExtra(WifiManager.EXTRA_MULTIPLE_NETWORKS_CHANGED,
+                        false /* defaultValue */)) {
+                        // only one network changed
+                        WifiConfiguration wifiConfiguration = intent
+                            .getParcelableExtra(WifiManager.EXTRA_WIFI_CONFIGURATION);
+                        if (mAccessPoint.matches(wifiConfiguration)) {
+                            mWifiConfig = wifiConfiguration;
+                        }
+                    }
+                    // fall through
                 case WifiManager.NETWORK_STATE_CHANGED_ACTION:
                 case WifiManager.RSSI_CHANGED_ACTION:
                     updateInfo();
+                    break;
             }
         }
     };
@@ -239,6 +255,8 @@
         mFilter = new IntentFilter();
         mFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
         mFilter.addAction(WifiManager.RSSI_CHANGED_ACTION);
+        mFilter.addAction(WifiManager.CONFIGURED_NETWORKS_CHANGED_ACTION);
+
         lifecycle.addObserver(this);
     }
 
@@ -334,7 +352,7 @@
             return;
         }
 
-        // Update whether the forgot button should be displayed.
+        // Update whether the forget button should be displayed.
         mButtonsPref.setButton1Visible(canForgetNetwork());
 
         refreshNetworkState();
@@ -520,6 +538,32 @@
         mConnectivityManagerWrapper.startCaptivePortalApp(mNetwork);
     }
 
+    @Override
+    public void onForget(WifiDialog dialog) {
+        // can't forget network from a 'modify' dialog
+    }
+
+    @Override
+    public void onSubmit(WifiDialog dialog) {
+        if (dialog.getController() != null) {
+            mWifiManager.save(dialog.getController().getConfig(), new WifiManager.ActionListener() {
+                @Override
+                public void onSuccess() {
+                }
+
+                @Override
+                public void onFailure(int reason) {
+                    Activity activity = mFragment.getActivity();
+                    if (activity != null) {
+                        Toast.makeText(activity,
+                                R.string.wifi_failed_save_message,
+                                Toast.LENGTH_SHORT).show();
+                    }
+                }
+            });
+        }
+    }
+
     /**
      * Wrapper for testing compatibility.
      */
diff --git a/src/com/android/settings/wifi/details/WifiNetworkDetailsFragment.java b/src/com/android/settings/wifi/details/WifiNetworkDetailsFragment.java
index 4918889..765bebc 100644
--- a/src/com/android/settings/wifi/details/WifiNetworkDetailsFragment.java
+++ b/src/com/android/settings/wifi/details/WifiNetworkDetailsFragment.java
@@ -15,17 +15,25 @@
  */
 package com.android.settings.wifi.details;
 
+import static com.android.settings.wifi.WifiSettings.WIFI_DIALOG_ID;
+
+import android.app.Dialog;
 import android.content.Context;
 import android.net.ConnectivityManager;
 import android.net.wifi.WifiManager;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
 import com.android.internal.logging.nano.MetricsProto;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.settings.R;
 import com.android.settings.dashboard.DashboardFragment;
 import com.android.settings.vpn2.ConnectivityManagerWrapperImpl;
-import com.android.settings.wifi.WifiDetailPreference;
+import com.android.settings.wifi.WifiConfigUiBase;
+import com.android.settings.wifi.WifiDialog;
 import com.android.settingslib.core.AbstractPreferenceController;
 import com.android.settingslib.wifi.AccessPoint;
 import java.util.ArrayList;
@@ -44,13 +52,9 @@
 
     private AccessPoint mAccessPoint;
     private WifiDetailPreferenceController mWifiDetailPreferenceController;
-    private WifiDetailActionBarObserver mWifiDetailActionBarObserver;
 
     @Override
     public void onAttach(Context context) {
-        mWifiDetailActionBarObserver = new WifiDetailActionBarObserver(context, this);
-        getLifecycle().addObserver(mWifiDetailActionBarObserver);
-
         mAccessPoint = new AccessPoint(context, getArguments());
         super.onAttach(context);
     }
@@ -71,6 +75,44 @@
     }
 
     @Override
+    public int getDialogMetricsCategory(int dialogId) {
+        if (dialogId == WIFI_DIALOG_ID) {
+            return MetricsEvent.DIALOG_WIFI_AP_EDIT;
+        }
+        return 0;
+    }
+
+    @Override
+    public Dialog onCreateDialog(int dialogId) {
+        if (getActivity() == null || mWifiDetailPreferenceController == null
+                || mAccessPoint == null) {
+            return null;
+        }
+        return WifiDialog.createModal(getActivity(), mWifiDetailPreferenceController, mAccessPoint,
+                WifiConfigUiBase.MODE_MODIFY);
+    }
+
+
+    @Override
+    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+        MenuItem item = menu.add(0, Menu.FIRST, 0, R.string.wifi_modify);
+        item.setIcon(R.drawable.ic_mode_edit);
+        item.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
+        super.onCreateOptionsMenu(menu, inflater);
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem menuItem) {
+        switch (menuItem.getItemId()) {
+            case Menu.FIRST:
+                showDialog(WIFI_DIALOG_ID);
+                return true;
+            default:
+                return super.onOptionsItemSelected(menuItem);
+        }
+    }
+
+    @Override
     protected List<AbstractPreferenceController> getPreferenceControllers(Context context) {
         ConnectivityManager cm = context.getSystemService(ConnectivityManager.class);
         mWifiDetailPreferenceController = WifiDetailPreferenceController.newInstance(
diff --git a/tests/robotests/src/com/android/settings/UtilsTest.java b/tests/robotests/src/com/android/settings/UtilsTest.java
index 33ead1f..19b87a1 100644
--- a/tests/robotests/src/com/android/settings/UtilsTest.java
+++ b/tests/robotests/src/com/android/settings/UtilsTest.java
@@ -174,6 +174,105 @@
     }
 
     @Test
+    public void testFormatRelativeTime_WithSeconds_ShowSeconds() {
+        final double testMillis = 40 * DateUtils.SECOND_IN_MILLIS;
+        final String expectedTime = "40 sec. ago";
+
+        assertThat(Utils.formatRelativeTime(mContext, testMillis, true).toString()).isEqualTo(
+                expectedTime);
+    }
+
+    @Test
+    public void testFormatRelativeTime_NoSeconds_DoNotShowSeconds() {
+        final double testMillis = 40 * DateUtils.SECOND_IN_MILLIS;
+        final String expectedTime = "1 min. ago";
+
+        assertThat(Utils.formatRelativeTime(mContext, testMillis, false).toString()).isEqualTo(
+                expectedTime);
+    }
+
+    @Test
+    public void testFormatRelativeTime_LessThanTwoMinutes_withSeconds() {
+        final double testMillis = 119 * DateUtils.SECOND_IN_MILLIS;
+        final String expectedTime = "119 sec. ago";
+
+        assertThat(Utils.formatRelativeTime(mContext, testMillis, true).toString()).isEqualTo(
+                expectedTime);
+    }
+
+    @Test
+    public void testFormatRelativeTime_LessThanTwoMinutes_NoSeconds() {
+        final double testMillis = 119 * DateUtils.SECOND_IN_MILLIS;
+        final String expectedTime = "2 min. ago";
+
+        assertThat(Utils.formatRelativeTime(mContext, testMillis, false).toString()).isEqualTo(
+                expectedTime);
+    }
+
+    @Test
+    public void testFormatRelativeTime_TwoMinutes_withSeconds() {
+        final double testMillis = 2 * DateUtils.MINUTE_IN_MILLIS;
+        final String expectedTime = "2 min. ago";
+
+        assertThat(Utils.formatRelativeTime(mContext, testMillis, true).toString()).isEqualTo(
+                expectedTime);
+    }
+
+    @Test
+    public void testFormatRelativeTime_LessThanTwoHours_withSeconds() {
+        final double testMillis = 119 * DateUtils.MINUTE_IN_MILLIS;
+        final String expectedTime = "119 min. ago";
+
+        assertThat(Utils.formatRelativeTime(mContext, testMillis, true).toString()).isEqualTo(
+                expectedTime);
+    }
+
+    @Test
+    public void testFormatRelativeTime_TwoHours_withSeconds() {
+        final double testMillis = 2 * DateUtils.HOUR_IN_MILLIS;
+        final String expectedTime = "2 hr. ago";
+
+        assertThat(Utils.formatRelativeTime(mContext, testMillis, true).toString()).isEqualTo(
+                expectedTime);
+    }
+
+    @Test
+    public void testFormatRelativeTime_LessThanTwoDays_withSeconds() {
+        final double testMillis = 47 * DateUtils.HOUR_IN_MILLIS;
+        final String expectedTime = "47 hr. ago";
+
+        assertThat(Utils.formatRelativeTime(mContext, testMillis, true).toString()).isEqualTo(
+                expectedTime);
+    }
+
+    @Test
+    public void testFormatRelativeTime_TwoDays_withSeconds() {
+        final double testMillis = 2 * DateUtils.DAY_IN_MILLIS;
+        final String expectedTime = "2 days ago";
+
+        assertThat(Utils.formatRelativeTime(mContext, testMillis, true).toString()).isEqualTo(
+                expectedTime);
+    }
+
+    @Test
+    public void testFormatRelativeTime_FormatZero_WithSeconds() {
+        final double testMillis = 0;
+        final String expectedTime = "0 sec. ago";
+
+        assertThat(Utils.formatRelativeTime(mContext, testMillis, true).toString()).isEqualTo(
+                expectedTime);
+    }
+
+    @Test
+    public void testFormatRelativeTime_FormatZero_NoSeconds() {
+        final double testMillis = 0;
+        final String expectedTime = "0 min. ago";
+
+        assertThat(Utils.formatRelativeTime(mContext, testMillis, false).toString()).isEqualTo(
+                expectedTime);
+    }
+
+    @Test
     public void testInitializeVolumeDoesntBreakOnNullVolume() {
         VolumeInfo info = new VolumeInfo("id", 0, new DiskInfo("id", 0), "");
         StorageManager storageManager = mock(StorageManager.class, RETURNS_DEEP_STUBS);
diff --git a/tests/robotests/src/com/android/settings/applications/RecentAppsPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/applications/RecentAppsPreferenceControllerTest.java
index 2510f20..5e85f9b 100644
--- a/tests/robotests/src/com/android/settings/applications/RecentAppsPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/applications/RecentAppsPreferenceControllerTest.java
@@ -249,8 +249,6 @@
         when(mUsageStatsManager.queryUsageStats(anyInt(), anyLong(), anyLong()))
             .thenReturn(stats);
 
-        when(mMockContext.getResources().getText(eq(R.string.recent_app_summary)))
-            .thenReturn(mContext.getResources().getText(R.string.recent_app_summary));
         final Configuration configuration = new Configuration();
         configuration.locale = Locale.US;
         when(mMockContext.getResources().getConfiguration()).thenReturn(configuration);
@@ -258,7 +256,7 @@
         mController = new RecentAppsPreferenceController(mMockContext, mAppState, null);
         mController.displayPreference(mScreen);
 
-        verify(mCategory).addPreference(argThat(summaryMatches("0m ago")));
+        verify(mCategory).addPreference(argThat(summaryMatches("0 min. ago")));
     }
 
     private static ArgumentMatcher<Preference> summaryMatches(String expected) {
diff --git a/tests/robotests/src/com/android/settings/development/DevelopmentSettingsDashboardFragmentTest.java b/tests/robotests/src/com/android/settings/development/DevelopmentSettingsDashboardFragmentTest.java
index 04ff721..a001aaf 100644
--- a/tests/robotests/src/com/android/settings/development/DevelopmentSettingsDashboardFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/development/DevelopmentSettingsDashboardFragmentTest.java
@@ -17,22 +17,32 @@
 package com.android.settings.development;
 
 import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
 
 import android.content.Context;
 import android.provider.SearchIndexableResource;
+import android.provider.Settings;
 
 import com.android.internal.logging.nano.MetricsProto;
 import com.android.settings.R;
 import com.android.settings.TestConfig;
 import com.android.settings.testutils.SettingsRobolectricTestRunner;
 import com.android.settings.testutils.shadow.SettingsShadowResources;
+import com.android.settings.widget.SwitchBar;
+import com.android.settings.widget.ToggleSwitch;
 import com.android.settingslib.development.DevelopmentSettingsEnabler;
 
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.MockitoAnnotations;
 import org.robolectric.RuntimeEnvironment;
 import org.robolectric.annotation.Config;
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
+import org.robolectric.util.ReflectionHelpers;
 
 import java.util.List;
 
@@ -44,11 +54,24 @@
         })
 public class DevelopmentSettingsDashboardFragmentTest {
 
+    private SwitchBar mSwitchBar;
+    private ToggleSwitch mSwitch;
+    private Context mContext;
     private DevelopmentSettingsDashboardFragment mDashboard;
 
     @Before
     public void setUp() {
-        mDashboard = new DevelopmentSettingsDashboardFragment();
+        MockitoAnnotations.initMocks(this);
+        mContext = RuntimeEnvironment.application;
+        mSwitchBar = new SwitchBar(mContext);
+        mSwitch = mSwitchBar.getSwitch();
+        mDashboard = spy(new DevelopmentSettingsDashboardFragment());
+        ReflectionHelpers.setField(mDashboard, "mSwitchBar", mSwitchBar);
+    }
+
+    @After
+    public void tearDown() {
+        ShadowEnableDevelopmentSettingWarningDialog.reset();
     }
 
     @Test
@@ -95,4 +118,62 @@
 
         assertThat(nonIndexableKeys).doesNotContain("development_prefs_screen");
     }
+
+    @Test
+    @Config(shadows = {
+            ShadowEnableDevelopmentSettingWarningDialog.class
+    })
+    public void onSwitchChanged_sameState_shouldDoNothing() {
+        when(mDashboard.getContext()).thenReturn(mContext);
+        Settings.Global.putInt(mContext.getContentResolver(),
+                Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 0);
+
+        mDashboard.onSwitchChanged(mSwitch, false /* isChecked */);
+        assertThat(ShadowEnableDevelopmentSettingWarningDialog.mShown).isFalse();
+    }
+
+    @Test
+    @Config(shadows = {
+            ShadowEnableDevelopmentSettingWarningDialog.class
+    })
+    public void onSwitchChanged_turnOn_shouldShowWarningDialog() {
+        when(mDashboard.getContext()).thenReturn(mContext);
+        Settings.Global.putInt(mContext.getContentResolver(),
+                Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 0);
+
+        mDashboard.onSwitchChanged(mSwitch, true /* isChecked */);
+        assertThat(ShadowEnableDevelopmentSettingWarningDialog.mShown).isTrue();
+    }
+
+    @Test
+    @Config(shadows = {
+            ShadowEnableDevelopmentSettingWarningDialog.class
+    })
+    public void onSwitchChanged_turnOff_shouldTurnOff() {
+        when(mDashboard.getContext()).thenReturn(mContext);
+        Settings.Global.putInt(mContext.getContentResolver(),
+                Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 1);
+
+        mDashboard.onSwitchChanged(mSwitch, false /* isChecked */);
+
+        assertThat(ShadowEnableDevelopmentSettingWarningDialog.mShown).isFalse();
+        assertThat(DevelopmentSettingsEnabler.isDevelopmentSettingsEnabled(mContext))
+                .isFalse();
+    }
+
+    @Implements(EnableDevelopmentSettingWarningDialog.class)
+    public static class ShadowEnableDevelopmentSettingWarningDialog {
+
+        static boolean mShown;
+
+        public static void reset() {
+            mShown = false;
+        }
+
+        @Implementation
+        public static void show(
+                DevelopmentSettingsDashboardFragment host) {
+            mShown = true;
+        }
+    }
 }
diff --git a/tests/robotests/src/com/android/settings/development/DevelopmentSwitchBarControllerTest.java b/tests/robotests/src/com/android/settings/development/DevelopmentSwitchBarControllerTest.java
index a53b836..6f79faf 100644
--- a/tests/robotests/src/com/android/settings/development/DevelopmentSwitchBarControllerTest.java
+++ b/tests/robotests/src/com/android/settings/development/DevelopmentSwitchBarControllerTest.java
@@ -17,6 +17,7 @@
 package com.android.settings.development;
 
 import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.when;
 
 import com.android.settings.TestConfig;
 import com.android.settings.testutils.SettingsRobolectricTestRunner;
@@ -45,6 +46,8 @@
 
     @Mock
     private DevelopmentSettings mSettings;
+    @Mock
+    private DevelopmentSettingsDashboardFragment mNewSettings;
     private Lifecycle mLifecycle;
     private SwitchBar mSwitchBar;
     private DevelopmentSwitchBarController mController;
@@ -77,6 +80,21 @@
     }
 
     @Test
+    public void runThroughLifecycle_v2_isMonkeyRun_shouldNotRegisterListener() {
+        ShadowUtils.setIsUserAMonkey(true);
+        mController = new DevelopmentSwitchBarController(mNewSettings, mSwitchBar,
+                true /* isAvailable */, mLifecycle);
+        final ArrayList<SwitchBar.OnSwitchChangeListener> listeners =
+                ReflectionHelpers.getField(mSwitchBar, "mSwitchChangeListeners");
+
+        mLifecycle.onStart();
+        assertThat(listeners).doesNotContain(mNewSettings);
+
+        mLifecycle.onStop();
+        assertThat(listeners).doesNotContain(mNewSettings);
+    }
+
+    @Test
     public void runThroughLifecycle_isNotMonkeyRun_shouldRegisterAndRemoveListener() {
         ShadowUtils.setIsUserAMonkey(false);
         mController = new DevelopmentSwitchBarController(mSettings, mSwitchBar,
@@ -92,6 +110,22 @@
     }
 
     @Test
+    public void runThroughLifecycle_v2_isNotMonkeyRun_shouldRegisterAndRemoveListener() {
+        when(mNewSettings.getContext()).thenReturn(RuntimeEnvironment.application);
+        ShadowUtils.setIsUserAMonkey(false);
+        mController = new DevelopmentSwitchBarController(mNewSettings, mSwitchBar,
+                true /* isAvailable */, mLifecycle);
+        final ArrayList<SwitchBar.OnSwitchChangeListener> listeners =
+                ReflectionHelpers.getField(mSwitchBar, "mSwitchChangeListeners");
+
+        mLifecycle.onStart();
+        assertThat(listeners).contains(mNewSettings);
+
+        mLifecycle.onStop();
+        assertThat(listeners).doesNotContain(mNewSettings);
+    }
+
+    @Test
     public void buildController_unavailable_shouldDisableSwitchBar() {
         ShadowUtils.setIsUserAMonkey(false);
         mController = new DevelopmentSwitchBarController(mSettings, mSwitchBar,
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BackgroundActivityPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BackgroundActivityPreferenceControllerTest.java
index 91f4a2b..86836f9 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/BackgroundActivityPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/BackgroundActivityPreferenceControllerTest.java
@@ -16,14 +16,25 @@
 
 package com.android.settings.fuelgauge;
 
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.robolectric.Shadows.shadowOf;
+
+import android.app.AlertDialog;
 import android.app.AppOpsManager;
 import android.app.admin.DevicePolicyManager;
 import android.content.Context;
+import android.content.DialogInterface;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.os.Build;
 import android.os.UserManager;
 import android.support.v14.preference.SwitchPreference;
+import android.widget.Button;
 
 import com.android.settings.R;
 import com.android.settings.TestConfig;
@@ -38,22 +49,17 @@
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
 import org.robolectric.annotation.Config;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
+import org.robolectric.shadows.ShadowAlertDialog;
+import org.robolectric.shadows.ShadowDialog;
+import org.robolectric.util.FragmentTestUtil;
 
 @RunWith(RobolectricTestRunner.class)
 @Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
 public class BackgroundActivityPreferenceControllerTest {
-    private static final int UID_NORMAL = 1234;
-    private static final int UID_SPECIAL = 2345;
+    private static final int UID_LOW_SDK = 1234;
+    private static final int UID_HIGH_SDK = 3456;
     private static final String HIGH_SDK_PACKAGE = "com.android.package.high";
     private static final String LOW_SDK_PACKAGE = "com.android.package.low";
-    private static final String[] PACKAGES_NORMAL = {LOW_SDK_PACKAGE};
-    private static final String[] PACKAGES_SPECIAL = {HIGH_SDK_PACKAGE, LOW_SDK_PACKAGE};
 
     @Mock(answer = Answers.RETURNS_DEEP_STUBS)
     private Context mContext;
@@ -71,6 +77,10 @@
     private DevicePolicyManager mDevicePolicyManager;
     @Mock
     private DevicePolicyManagerWrapper mDevicePolicyManagerWrapper;
+    @Mock
+    private AdvancedPowerUsageDetail mFragment;
+    @Mock
+    private PowerWhitelistBackend mPowerWhitelistBackend;
     private BackgroundActivityPreferenceController mController;
     private SwitchPreference mPreference;
     private Context mShadowContext;
@@ -85,19 +95,19 @@
         when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager);
         when(mContext.getSystemService(Context.DEVICE_POLICY_SERVICE)).thenReturn(
                 mDevicePolicyManager);
-        when(mPackageManager.getPackagesForUid(UID_NORMAL)).thenReturn(PACKAGES_NORMAL);
-        when(mPackageManager.getPackagesForUid(UID_SPECIAL)).thenReturn(PACKAGES_SPECIAL);
 
         when(mPackageManager.getApplicationInfo(HIGH_SDK_PACKAGE, PackageManager.GET_META_DATA))
                 .thenReturn(mHighApplicationInfo);
         when(mPackageManager.getApplicationInfo(LOW_SDK_PACKAGE, PackageManager.GET_META_DATA))
                 .thenReturn(mLowApplicationInfo);
+
+        when(mPowerWhitelistBackend.isWhitelisted(LOW_SDK_PACKAGE)).thenReturn(false);
         mHighApplicationInfo.targetSdkVersion = Build.VERSION_CODES.O;
         mLowApplicationInfo.targetSdkVersion = Build.VERSION_CODES.L;
 
         mPreference = new SwitchPreference(mShadowContext);
-        mController = spy(new BackgroundActivityPreferenceController(mContext, UID_NORMAL));
-        mController.isAvailable();
+        mController = spy(new BackgroundActivityPreferenceController(
+                mContext, mFragment, UID_LOW_SDK, LOW_SDK_PACKAGE, mPowerWhitelistBackend));
         mController.mDpm = mDevicePolicyManagerWrapper;
     }
 
@@ -105,49 +115,66 @@
     public void testOnPreferenceChange_TurnOnCheck_MethodInvoked() {
         mController.onPreferenceChange(mPreference, true);
 
-        verify(mAppOpsManager).setMode(AppOpsManager.OP_RUN_IN_BACKGROUND, UID_NORMAL,
-                mController.getTargetPackage(), AppOpsManager.MODE_ALLOWED);
-        verify(mController).updateSummary(mPreference);
+        verify(mAppOpsManager).setMode(AppOpsManager.OP_RUN_IN_BACKGROUND, UID_LOW_SDK,
+                LOW_SDK_PACKAGE, AppOpsManager.MODE_ALLOWED);
+        verify(mAppOpsManager).setMode(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, UID_LOW_SDK,
+                LOW_SDK_PACKAGE, AppOpsManager.MODE_ALLOWED);
+
+        assertThat(mPreference.getSummary())
+                .isEqualTo(mShadowContext.getText(R.string.background_activity_summary_on));
     }
 
     @Test
-    public void testOnPreferenceChange_TurnOffCheck_MethodInvoked() {
-        mController.onPreferenceChange(mPreference, false);
-
-        verify(mAppOpsManager).setMode(AppOpsManager.OP_RUN_IN_BACKGROUND, UID_NORMAL,
-                mController.getTargetPackage(), AppOpsManager.MODE_IGNORED);
-        verify(mController).updateSummary(mPreference);
+    public void testOnPreferenceChange_TurnOnCheckHighSDK_MethodInvoked() {
+        mController = new BackgroundActivityPreferenceController(mContext, mFragment, UID_HIGH_SDK,
+                HIGH_SDK_PACKAGE, mPowerWhitelistBackend);
+        mController.onPreferenceChange(mPreference, true);
+        verify(mAppOpsManager).setMode(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, UID_HIGH_SDK,
+                HIGH_SDK_PACKAGE, AppOpsManager.MODE_ALLOWED);
+        verify(mAppOpsManager, never()).setMode(AppOpsManager.OP_RUN_IN_BACKGROUND, UID_HIGH_SDK,
+                HIGH_SDK_PACKAGE, AppOpsManager.MODE_ALLOWED);
+        assertThat(mPreference.getSummary())
+                .isEqualTo(mShadowContext.getText(R.string.background_activity_summary_on));
     }
 
     @Test
     public void testUpdateState_CheckOn_SetCheckedTrue() {
-        when(mAppOpsManager
-                .checkOpNoThrow(AppOpsManager.OP_RUN_IN_BACKGROUND, UID_NORMAL, LOW_SDK_PACKAGE))
-                .thenReturn(AppOpsManager.MODE_DEFAULT);
+        when(mAppOpsManager.checkOpNoThrow(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, UID_LOW_SDK,
+                LOW_SDK_PACKAGE)).thenReturn(AppOpsManager.MODE_ALLOWED);
 
         mController.updateState(mPreference);
 
         assertThat(mPreference.isChecked()).isTrue();
+        assertThat(mPreference.isEnabled()).isTrue();
         verify(mController).updateSummary(mPreference);
     }
 
     @Test
     public void testUpdateState_CheckOff_SetCheckedFalse() {
-        when(mAppOpsManager
-                .checkOpNoThrow(AppOpsManager.OP_RUN_IN_BACKGROUND, UID_NORMAL, LOW_SDK_PACKAGE))
-                .thenReturn(AppOpsManager.MODE_IGNORED);
+        when(mAppOpsManager.checkOpNoThrow(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, UID_LOW_SDK,
+                LOW_SDK_PACKAGE)).thenReturn(AppOpsManager.MODE_IGNORED);
 
         mController.updateState(mPreference);
 
         assertThat(mPreference.isChecked()).isFalse();
+        assertThat(mPreference.isEnabled()).isTrue();
         verify(mController).updateSummary(mPreference);
     }
 
     @Test
+    public void testUpdateState_whitelisted() {
+        when(mPowerWhitelistBackend.isWhitelisted(LOW_SDK_PACKAGE)).thenReturn(true);
+        mController.updateState(mPreference);
+        assertThat(mPreference.isChecked()).isTrue();
+        assertThat(mPreference.isEnabled()).isFalse();
+        assertThat(mPreference.getSummary()).isEqualTo(
+                mShadowContext.getText(R.string.background_activity_summary_whitelisted));
+    }
+
+    @Test
     public void testUpdateSummary_modeError_showSummaryDisabled() {
-        when(mAppOpsManager
-                .checkOpNoThrow(AppOpsManager.OP_RUN_IN_BACKGROUND, UID_NORMAL, LOW_SDK_PACKAGE))
-                .thenReturn(AppOpsManager.MODE_ERRORED);
+        when(mAppOpsManager.checkOpNoThrow(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, UID_LOW_SDK,
+                LOW_SDK_PACKAGE)).thenReturn(AppOpsManager.MODE_ERRORED);
         final CharSequence expectedSummary = mShadowContext.getText(
                 R.string.background_activity_summary_disabled);
         mController.updateSummary(mPreference);
@@ -157,9 +184,8 @@
 
     @Test
     public void testUpdateSummary_modeDefault_showSummaryOn() {
-        when(mAppOpsManager
-                .checkOpNoThrow(AppOpsManager.OP_RUN_IN_BACKGROUND, UID_NORMAL, LOW_SDK_PACKAGE))
-                .thenReturn(AppOpsManager.MODE_DEFAULT);
+        when(mAppOpsManager.checkOpNoThrow(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, UID_LOW_SDK,
+                LOW_SDK_PACKAGE)).thenReturn(AppOpsManager.MODE_DEFAULT);
         final CharSequence expectedSummary = mShadowContext.getText(
                 R.string.background_activity_summary_on);
 
@@ -170,9 +196,8 @@
 
     @Test
     public void testUpdateSummary_modeIgnored_showSummaryOff() {
-        when(mAppOpsManager
-                .checkOpNoThrow(AppOpsManager.OP_RUN_IN_BACKGROUND, UID_NORMAL, LOW_SDK_PACKAGE))
-                .thenReturn(AppOpsManager.MODE_IGNORED);
+        when(mAppOpsManager.checkOpNoThrow(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, UID_LOW_SDK,
+                LOW_SDK_PACKAGE)).thenReturn(AppOpsManager.MODE_IGNORED);
         final CharSequence expectedSummary = mShadowContext.getText(
                 R.string.background_activity_summary_off);
 
@@ -182,31 +207,30 @@
     }
 
     @Test
-    public void testIsPackageAvailable_SdkLowerThanO_ReturnTrue() {
+    public void testIsLegacyApp_SdkLowerThanO_ReturnTrue() {
         assertThat(mController.isLegacyApp(LOW_SDK_PACKAGE)).isTrue();
     }
 
     @Test
-    public void testIsPackageAvailable_SdkLargerOrEqualThanO_ReturnFalse() {
+    public void testIsLegacyApp_SdkLargerOrEqualThanO_ReturnFalse() {
         assertThat(mController.isLegacyApp(HIGH_SDK_PACKAGE)).isFalse();
     }
 
     @Test
-    public void testMultiplePackages_ReturnStatusForTargetPackage() {
-        mController = new BackgroundActivityPreferenceController(mContext, UID_SPECIAL);
-        mController.mDpm = mDevicePolicyManagerWrapper;
-        when(mAppOpsManager
-                .checkOpNoThrow(AppOpsManager.OP_RUN_IN_BACKGROUND, UID_SPECIAL, LOW_SDK_PACKAGE))
-                .thenReturn(AppOpsManager.MODE_ALLOWED);
-        when(mAppOpsManager
-                .checkOpNoThrow(AppOpsManager.OP_RUN_IN_BACKGROUND, UID_SPECIAL, HIGH_SDK_PACKAGE))
-                .thenReturn(AppOpsManager.MODE_IGNORED);
+    public void testIsAvailable_ReturnTrue() {
+        assertThat(mController.isAvailable()).isTrue();
+    }
 
-        final boolean available = mController.isAvailable();
-        mController.updateState(mPreference);
-
-        assertThat(available).isTrue();
-        // Should get status from LOW_SDK_PACKAGE
-        assertThat(mPreference.isChecked()).isTrue();
+    @Test
+    public void testWarningDialog() {
+        BackgroundActivityPreferenceController.WarningDialogFragment dialogFragment =
+                new BackgroundActivityPreferenceController.WarningDialogFragment();
+        dialogFragment.setTargetFragment(mFragment, 0);
+        FragmentTestUtil.startFragment(dialogFragment);
+        final AlertDialog dialog = (AlertDialog) ShadowDialog.getLatestDialog();
+        ShadowAlertDialog shadowDialog = shadowOf(dialog);
+        final Button okButton = dialog.getButton(DialogInterface.BUTTON_POSITIVE);
+        shadowDialog.clickOn(okButton.getId());
+        verify(mFragment).onLimitBackgroundActivity();
     }
 }
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageSummaryTest.java b/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageSummaryTest.java
index db4fb6d..89a4208 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageSummaryTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageSummaryTest.java
@@ -411,18 +411,11 @@
 
     @Test
     public void testUpdateLastFullChargePreference_showCorrectSummary() {
-        final CharSequence formattedString = mRealContext.getText(
-                R.string.power_last_full_charge_summary);
-        final CharSequence timeSequence = Utils.formatElapsedTime(mRealContext,
-                TIME_SINCE_LAST_FULL_CHARGE_MS, false);
-        final CharSequence expectedSummary = TextUtils.expandTemplate(
-                formattedString, timeSequence);
-        doReturn(formattedString).when(mFragment).getText(R.string.power_last_full_charge_summary);
         doReturn(mRealContext).when(mFragment).getContext();
 
         mFragment.updateLastFullChargePreference(TIME_SINCE_LAST_FULL_CHARGE_MS);
 
-        assertThat(mLastFullChargePref.getSubtitle()).isEqualTo(expectedSummary);
+        assertThat(mLastFullChargePref.getSubtitle()).isEqualTo("2 hr. ago");
     }
 
     @Test
diff --git a/tests/robotests/src/com/android/settings/wifi/details/WifiDetailActionBarObserverTest.java b/tests/robotests/src/com/android/settings/wifi/details/WifiDetailActionBarObserverTest.java
deleted file mode 100644
index c573d3c..0000000
--- a/tests/robotests/src/com/android/settings/wifi/details/WifiDetailActionBarObserverTest.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (C) 2017 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.wifi.details;
-
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.app.ActionBar;
-import android.app.Activity;
-import android.content.Context;
-import android.os.Bundle;
-import com.android.settings.R;
-import com.android.settings.TestConfig;
-import com.android.settings.testutils.SettingsRobolectricTestRunner;
-import com.android.settingslib.core.lifecycle.Lifecycle;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.robolectric.RuntimeEnvironment;
-import org.robolectric.annotation.Config;
-
-@RunWith(SettingsRobolectricTestRunner.class)
-@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
-public class WifiDetailActionBarObserverTest {
-
-    @Mock private Bundle mockBundle;
-    @Mock private Activity mockActivity;
-    @Mock private ActionBar mockActionBar;
-    @Mock private WifiNetworkDetailsFragment mockFragment;
-
-    private Context mContext = RuntimeEnvironment.application;
-    private Lifecycle mLifecycle;
-    private WifiDetailActionBarObserver mObserver;
-
-    @Before
-    public void setUp() {
-        MockitoAnnotations.initMocks(this);
-
-        mLifecycle = new Lifecycle();
-
-        when(mockFragment.getActivity()).thenReturn(mockActivity);
-        when(mockActivity.getActionBar()).thenReturn(mockActionBar);
-
-        mObserver = new WifiDetailActionBarObserver(mContext, mockFragment);
-        mLifecycle.addObserver(mObserver);
-    }
-
-    @Test
-    public void actionBarIsSetToNetworkInfo() {
-        mLifecycle.onCreate(mockBundle);
-
-        verify(mockActionBar).setTitle(mContext.getString(R.string.wifi_details_title));
-    }
-}