Merge "Add ability to show/hide items for Special Access."
diff --git a/res/layout/data_usage_bytes_editor.xml b/res/layout/data_usage_bytes_editor.xml
index af2d59b..2878c3e 100644
--- a/res/layout/data_usage_bytes_editor.xml
+++ b/res/layout/data_usage_bytes_editor.xml
@@ -37,6 +37,7 @@
         android:id="@+id/size_spinner"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_gravity="center_vertical" />
+        android:layout_gravity="center_vertical"
+        android:entries="@array/bytes_picker_sizes" />
 
 </LinearLayout>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index a809c78..3dc342b 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -8505,6 +8505,11 @@
     <!-- Text for the setting on whether you can type text into notifications without unlocking the device. -->
     <string name="lockscreen_remote_input">If device is locked, prevent typing replies or other text in notifications</string>
 
+    <string-array name="bytes_picker_sizes" translatable="false">
+        <item>@*android:string/megabyteShort</item>
+        <item>@*android:string/gigabyteShort</item>
+    </string-array>
+
     <!-- [CHAR LIMIT=30] Label for setting to control the default spell checker -->
     <string name="default_spell_checker">Default spell checker</string>
 
diff --git a/res/xml/security_settings_v2.xml b/res/xml/security_settings_v2.xml
index 155ee70..30e829d 100644
--- a/res/xml/security_settings_v2.xml
+++ b/res/xml/security_settings_v2.xml
@@ -28,6 +28,22 @@
         android:title="@string/security_status_title" />
 
     <!-- TODO Need security section -->
+    <PreferenceCategory
+        android:key="security_category"
+        android:title="@string/lock_settings_title">
+
+        <!-- security_settings_chooser -->
+        <com.android.settings.widget.GearPreference
+            android:key="unlock_set_or_change"
+            android:title="@string/unlock_set_unlock_launch_picker_title"
+            android:summary="@string/unlock_set_unlock_mode_none"
+            settings:keywords="@string/keywords_lockscreen" />
+
+        <Preference android:key="lockscreen_preferences"
+                    android:title="@string/lockscreen_settings_title"
+                    android:fragment="com.android.settings.security.LockscreenDashboardFragment"/>
+
+    </PreferenceCategory>
 
     <!-- security_settings_misc.xml -->
     <PreferenceCategory
diff --git a/src/com/android/settings/dashboard/DashboardFragment.java b/src/com/android/settings/dashboard/DashboardFragment.java
index 3e1e881..6a88a38 100644
--- a/src/com/android/settings/dashboard/DashboardFragment.java
+++ b/src/com/android/settings/dashboard/DashboardFragment.java
@@ -54,7 +54,7 @@
         SummaryLoader.SummaryConsumer {
     private static final String TAG = "DashboardFragment";
 
-    private final Map<Class, AbstractPreferenceController> mPreferenceControllers =
+    private final Map<Class, List<AbstractPreferenceController>> mPreferenceControllers =
             new ArrayMap<>();
     private final Set<String> mDashboardTilePrefKeys = new ArraySet<>();
 
@@ -156,14 +156,17 @@
 
     @Override
     public boolean onPreferenceTreeClick(Preference preference) {
-        Collection<AbstractPreferenceController> controllers = mPreferenceControllers.values();
+        Collection<List<AbstractPreferenceController>> controllers =
+                mPreferenceControllers.values();
         // If preference contains intent, log it before handling.
         mMetricsFeatureProvider.logDashboardStartIntent(
                 getContext(), preference.getIntent(), getMetricsCategory());
         // Give all controllers a chance to handle click.
-        for (AbstractPreferenceController controller : controllers) {
-            if (controller.handlePreferenceTreeClick(preference)) {
-                return true;
+        for (List<AbstractPreferenceController> controllerList : controllers) {
+            for (AbstractPreferenceController controller : controllerList) {
+                if (controller.handlePreferenceTreeClick(preference)) {
+                    return true;
+                }
             }
         }
         return super.onPreferenceTreeClick(preference);
@@ -189,12 +192,23 @@
     protected abstract int getPreferenceScreenResId();
 
     protected <T extends AbstractPreferenceController> T getPreferenceController(Class<T> clazz) {
-        AbstractPreferenceController controller = mPreferenceControllers.get(clazz);
-        return (T) controller;
+        List<AbstractPreferenceController> controllerList = mPreferenceControllers.get(clazz);
+        if (controllerList != null) {
+            if (controllerList.size() > 1) {
+                Log.w(TAG, "Multiple controllers of Class " + clazz.getSimpleName()
+                        + " found, returning first one.");
+            }
+            return (T) controllerList.get(0);
+        }
+
+        return null;
     }
 
     protected void addPreferenceController(AbstractPreferenceController controller) {
-        mPreferenceControllers.put(controller.getClass(), controller);
+        if (mPreferenceControllers.get(controller.getClass()) == null) {
+            mPreferenceControllers.put(controller.getClass(), new ArrayList<>());
+        }
+        mPreferenceControllers.get(controller.getClass()).add(controller);
     }
 
     /**
@@ -249,31 +263,32 @@
         }
         addPreferencesFromResource(resId);
         final PreferenceScreen screen = getPreferenceScreen();
-        Collection<AbstractPreferenceController> controllers = mPreferenceControllers.values();
-        for (AbstractPreferenceController controller : controllers) {
-            controller.displayPreference(screen);
-        }
+        mPreferenceControllers.values().stream().flatMap(Collection::stream).forEach(
+                controller -> controller.displayPreference(screen));
     }
 
     /**
      * Update state of each preference managed by PreferenceController.
      */
     protected void updatePreferenceStates() {
-        Collection<AbstractPreferenceController> controllers = mPreferenceControllers.values();
         final PreferenceScreen screen = getPreferenceScreen();
-        for (AbstractPreferenceController controller : controllers) {
-            if (!controller.isAvailable()) {
-                continue;
-            }
-            final String key = controller.getPreferenceKey();
+        Collection<List<AbstractPreferenceController>> controllerLists =
+                mPreferenceControllers.values();
+        for (List<AbstractPreferenceController> controllerList : controllerLists) {
+            for (AbstractPreferenceController controller : controllerList) {
+                if (!controller.isAvailable()) {
+                    continue;
+                }
+                final String key = controller.getPreferenceKey();
 
-            final Preference preference = screen.findPreference(key);
-            if (preference == null) {
-                Log.d(TAG, String.format("Cannot find preference with key %s in Controller %s",
-                        key, controller.getClass().getSimpleName()));
-                continue;
+                final Preference preference = screen.findPreference(key);
+                if (preference == null) {
+                    Log.d(TAG, String.format("Cannot find preference with key %s in Controller %s",
+                            key, controller.getClass().getSimpleName()));
+                    continue;
+                }
+                controller.updateState(preference);
             }
-            controller.updateState(preference);
         }
     }
 
diff --git a/src/com/android/settings/deviceinfo/StorageItemPreference.java b/src/com/android/settings/deviceinfo/StorageItemPreference.java
index d0114e3..3dcf935 100644
--- a/src/com/android/settings/deviceinfo/StorageItemPreference.java
+++ b/src/com/android/settings/deviceinfo/StorageItemPreference.java
@@ -18,7 +18,6 @@
 
 import android.content.Context;
 import android.content.res.Resources;
-import android.icu.util.MeasureUnit;
 import android.support.v7.preference.Preference;
 import android.support.v7.preference.PreferenceViewHolder;
 import android.util.AttributeSet;
@@ -52,7 +51,7 @@
                 FileSizeFormatter.formatFileSize(
                         getContext(),
                         size,
-                        MeasureUnit.GIGABYTE,
+                        getGigabyteSuffix(getContext().getResources()),
                         FileSizeFormatter.GIGABYTE_IN_BYTES));
         if (total == 0) {
             mProgressPercent = 0;
@@ -76,4 +75,8 @@
         updateProgressBar();
         super.onBindViewHolder(view);
     }
+
+    private static int getGigabyteSuffix(Resources res) {
+        return res.getIdentifier("gigabyteShort", "string", "android");
+    }
 }
diff --git a/src/com/android/settings/security/SecuritySettingsV2.java b/src/com/android/settings/security/SecuritySettingsV2.java
index 91a8cc7..002e447 100644
--- a/src/com/android/settings/security/SecuritySettingsV2.java
+++ b/src/com/android/settings/security/SecuritySettingsV2.java
@@ -41,7 +41,7 @@
 import com.android.settings.search.SearchIndexableRaw;
 import com.android.settings.security.screenlock.ScreenLockSettings;
 import com.android.settings.security.trustagent.ManageTrustAgentsPreferenceController;
-import com.android.settings.security.trustagent.TrustAgentManager;
+import com.android.settings.security.trustagent.TrustAgentListPreferenceController;
 import com.android.settings.widget.GearPreference;
 import com.android.settingslib.RestrictedLockUtils;
 import com.android.settingslib.RestrictedPreference;
@@ -58,8 +58,6 @@
 
     private static final String TAG = "SecuritySettingsV2";
 
-    private static final String TRUST_AGENT_CLICK_INTENT = "trust_agent_click_intent";
-
     // Lock Settings
     private static final String KEY_UNLOCK_SET_OR_CHANGE = "unlock_set_or_change";
     private static final String KEY_UNLOCK_SET_OR_CHANGE_PROFILE = "unlock_set_or_change_profile";
@@ -73,16 +71,13 @@
     private static final String KEY_LOCATION = "location";
 
     private static final int SET_OR_CHANGE_LOCK_METHOD_REQUEST = 123;
-    private static final int CHANGE_TRUST_AGENT_SETTINGS = 126;
+    public static final int CHANGE_TRUST_AGENT_SETTINGS = 126;
     private static final int SET_OR_CHANGE_LOCK_METHOD_REQUEST_PROFILE = 127;
     private static final int UNIFY_LOCK_CONFIRM_DEVICE_REQUEST = 128;
     private static final int UNIFY_LOCK_CONFIRM_PROFILE_REQUEST = 129;
     private static final int UNUNIFY_LOCK_CONFIRM_DEVICE_REQUEST = 130;
     private static final String TAG_UNIFICATION_DIALOG = "unification_dialog";
 
-    // Misc Settings
-    private static final String KEY_TRUST_AGENT = "trust_agent";
-
     // Security status
     private static final String KEY_SECURITY_STATUS = "security_status";
     private static final String SECURITY_STATUS_KEY_PREFIX = "security_status_";
@@ -101,7 +96,6 @@
     private DashboardFeatureProvider mDashboardFeatureProvider;
     private DevicePolicyManager mDPM;
     private SecurityFeatureProvider mSecurityFeatureProvider;
-    private TrustAgentManager mTrustAgentManager;
     private UserManager mUm;
 
     private ChooseLockSettingsHelper mChooseLockSettingsHelper;
@@ -111,8 +105,6 @@
     private SwitchPreference mVisiblePatternProfile;
     private RestrictedSwitchPreference mUnifyProfile;
 
-    private Intent mTrustAgentClickIntent;
-
     private int mProfileChallengeUserId;
 
     private String mCurrentDevicePassword;
@@ -127,6 +119,7 @@
     private ScreenPinningPreferenceController mScreenPinningPreferenceController;
     private SimLockPreferenceController mSimLockPreferenceController;
     private ShowPasswordPreferenceController mShowPasswordPreferenceController;
+    private TrustAgentListPreferenceController mTrustAgentListPreferenceController;
 
     @Override
     public int getMetricsCategory() {
@@ -145,7 +138,7 @@
         mDashboardFeatureProvider = FeatureFactory.getFactory(context)
                 .getDashboardFeatureProvider(context);
 
-        mTrustAgentManager = mSecurityFeatureProvider.getTrustAgentManager();
+        mChooseLockSettingsHelper = new ChooseLockSettingsHelper(getActivity());
     }
 
     @Override
@@ -172,21 +165,11 @@
         mShowPasswordPreferenceController = new ShowPasswordPreferenceController(context);
         mEncryptionStatusPreferenceController = new EncryptionStatusPreferenceController(
                 context, PREF_KEY_ENCRYPTION_SECURITY_PAGE);
+        mTrustAgentListPreferenceController = new TrustAgentListPreferenceController(getActivity(),
+                this /* host */, getLifecycle());
         return null;
     }
 
-    @Override
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-
-        mChooseLockSettingsHelper = new ChooseLockSettingsHelper(getActivity());
-
-        if (savedInstanceState != null
-                && savedInstanceState.containsKey(TRUST_AGENT_CLICK_INTENT)) {
-            mTrustAgentClickIntent = savedInstanceState.getParcelable(TRUST_AGENT_CLICK_INTENT);
-        }
-    }
-
     private static int getResIdForLockUnlockScreen(LockPatternUtils lockPatternUtils,
             ManagedLockPasswordProvider managedPasswordProvider, int userId) {
         final boolean isMyUser = userId == MY_USER_ID;
@@ -237,6 +220,7 @@
         }
         addPreferencesFromResource(R.xml.security_settings_v2);
         root = getPreferenceScreen();
+        mTrustAgentListPreferenceController.displayPreference(root);
 
         // Add options for lock/unlock screen
         final int resid = getResIdForLockUnlockScreen(mLockPatternUtils,
@@ -272,7 +256,6 @@
                         mProfileChallengeUserId);
             }
         }
-
         Preference unlockSetOrChange = findPreference(KEY_UNLOCK_SET_OR_CHANGE);
         if (unlockSetOrChange instanceof GearPreference) {
             ((GearPreference) unlockSetOrChange).setOnGearClickListener(this);
@@ -284,7 +267,6 @@
                 root.findPreference(KEY_SECURITY_CATEGORY);
         if (securityCategory != null) {
             maybeAddFingerprintPreference(securityCategory, UserHandle.myUserId());
-            addTrustAgentSettings(securityCategory);
             setLockscreenPreferencesSummary(securityCategory);
         }
 
@@ -379,34 +361,6 @@
         }
     }
 
-    // Return the number of trust agents being added
-    private int addTrustAgentSettings(PreferenceGroup securityCategory) {
-        final boolean hasSecurity = mLockPatternUtils.isSecure(MY_USER_ID);
-        final List<TrustAgentManager.TrustAgentComponentInfo> agents =
-                mTrustAgentManager.getActiveTrustAgents(getActivity(), mLockPatternUtils);
-        for (TrustAgentManager.TrustAgentComponentInfo agent : agents) {
-            final RestrictedPreference trustAgentPreference =
-                    new RestrictedPreference(securityCategory.getContext());
-            trustAgentPreference.setKey(KEY_TRUST_AGENT);
-            trustAgentPreference.setTitle(agent.title);
-            trustAgentPreference.setSummary(agent.summary);
-            // Create intent for this preference.
-            Intent intent = new Intent();
-            intent.setComponent(agent.componentName);
-            intent.setAction(Intent.ACTION_MAIN);
-            trustAgentPreference.setIntent(intent);
-            // Add preference to the settings menu.
-            securityCategory.addPreference(trustAgentPreference);
-
-            trustAgentPreference.setDisabledByAdmin(agent.admin);
-            if (!trustAgentPreference.isDisabledByAdmin() && !hasSecurity) {
-                trustAgentPreference.setEnabled(false);
-                trustAgentPreference.setSummary(R.string.disabled_because_no_backup_security);
-            }
-        }
-        return agents.size();
-    }
-
     @Override
     public void onGearClick(GearPreference p) {
         if (KEY_UNLOCK_SET_OR_CHANGE.equals(p.getKey())) {
@@ -415,14 +369,6 @@
     }
 
     @Override
-    public void onSaveInstanceState(Bundle outState) {
-        super.onSaveInstanceState(outState);
-        if (mTrustAgentClickIntent != null) {
-            outState.putParcelable(TRUST_AGENT_CLICK_INTENT, mTrustAgentClickIntent);
-        }
-    }
-
-    @Override
     public void onResume() {
         super.onResume();
 
@@ -445,7 +391,7 @@
         final Preference encryptionStatusPref = getPreferenceScreen().findPreference(
                 mEncryptionStatusPreferenceController.getPreferenceKey());
         mEncryptionStatusPreferenceController.updateState(encryptionStatusPref);
-
+        mTrustAgentListPreferenceController.onResume();
         mLocationController.updateSummary();
     }
 
@@ -465,6 +411,9 @@
 
     @Override
     public boolean onPreferenceTreeClick(Preference preference) {
+        if (mTrustAgentListPreferenceController.handlePreferenceTreeClick(preference)) {
+            return true;
+        }
         final String key = preference.getKey();
         if (KEY_UNLOCK_SET_OR_CHANGE.equals(key)) {
             // TODO(b/35930129): Remove once existing password can be passed into vold directly.
@@ -491,17 +440,6 @@
             startFragment(this, ChooseLockGeneric.ChooseLockGenericFragment.class.getName(),
                     R.string.lock_settings_picker_title_profile,
                     SET_OR_CHANGE_LOCK_METHOD_REQUEST_PROFILE, extras);
-        } else if (KEY_TRUST_AGENT.equals(key)) {
-            ChooseLockSettingsHelper helper =
-                    new ChooseLockSettingsHelper(this.getActivity(), this);
-            mTrustAgentClickIntent = preference.getIntent();
-            boolean confirmationLaunched = helper.launchConfirmationActivity(
-                    CHANGE_TRUST_AGENT_SETTINGS, preference.getTitle());
-            if (!confirmationLaunched && mTrustAgentClickIntent != null) {
-                // If this returns false, it means no password confirmation is required.
-                startActivity(mTrustAgentClickIntent);
-                mTrustAgentClickIntent = null;
-            }
         } else {
             // If we didn't handle it, let preferences handle it.
             return super.onPreferenceTreeClick(preference);
@@ -516,10 +454,7 @@
     public void onActivityResult(int requestCode, int resultCode, Intent data) {
         super.onActivityResult(requestCode, resultCode, data);
         if (requestCode == CHANGE_TRUST_AGENT_SETTINGS && resultCode == Activity.RESULT_OK) {
-            if (mTrustAgentClickIntent != null) {
-                startActivity(mTrustAgentClickIntent);
-                mTrustAgentClickIntent = null;
-            }
+            mTrustAgentListPreferenceController.handleActivityResult(resultCode);
             return;
         } else if (requestCode == UNIFY_LOCK_CONFIRM_DEVICE_REQUEST
                 && resultCode == Activity.RESULT_OK) {
@@ -760,15 +695,9 @@
         @Override
         public List<String> getNonIndexableKeys(Context context) {
             final List<String> keys = super.getNonIndexableKeys(context);
-            final LockPatternUtils lockPatternUtils = new LockPatternUtils(context);
 
             new SimLockPreferenceController(context).updateNonIndexableKeys(keys);
 
-            // TrustAgent settings disappear when the user has no primary security.
-            if (!lockPatternUtils.isSecure(MY_USER_ID)) {
-                keys.add(KEY_TRUST_AGENT);
-            }
-
             if (!(new EnterprisePrivacyPreferenceController(context))
                     .isAvailable()) {
                 keys.add(KEY_ENTERPRISE_PRIVACY);
diff --git a/src/com/android/settings/security/trustagent/TrustAgentListPreferenceController.java b/src/com/android/settings/security/trustagent/TrustAgentListPreferenceController.java
new file mode 100644
index 0000000..d99757b
--- /dev/null
+++ b/src/com/android/settings/security/trustagent/TrustAgentListPreferenceController.java
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2018 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.security.trustagent;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.UserHandle;
+import android.support.annotation.VisibleForTesting;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.PreferenceCategory;
+import android.support.v7.preference.PreferenceScreen;
+import android.text.TextUtils;
+
+import com.android.internal.widget.LockPatternUtils;
+import com.android.settings.R;
+import com.android.settings.overlay.FeatureFactory;
+import com.android.settings.password.ChooseLockSettingsHelper;
+import com.android.settings.security.SecurityFeatureProvider;
+import com.android.settings.security.SecuritySettingsV2;
+import com.android.settingslib.RestrictedPreference;
+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.OnCreate;
+import com.android.settingslib.core.lifecycle.events.OnResume;
+import com.android.settingslib.core.lifecycle.events.OnSaveInstanceState;
+
+import java.util.List;
+
+public class TrustAgentListPreferenceController extends AbstractPreferenceController
+        implements LifecycleObserver, OnSaveInstanceState, OnCreate, OnResume {
+
+    private static final String TRUST_AGENT_CLICK_INTENT = "trust_agent_click_intent";
+    @VisibleForTesting
+    static final String PREF_KEY_TRUST_AGENT = "trust_agent";
+    @VisibleForTesting
+    static final String PREF_KEY_SECURITY_CATEGORY = "security_category";
+    private static final int MY_USER_ID = UserHandle.myUserId();
+
+    private final LockPatternUtils mLockPatternUtils;
+    private final TrustAgentManager mTrustAgentManager;
+    private final Activity mActivity;
+    private final SecuritySettingsV2 mHost;
+
+    private Intent mTrustAgentClickIntent;
+    private PreferenceCategory mSecurityCategory;
+
+    public TrustAgentListPreferenceController(Activity activity, SecuritySettingsV2 host,
+            Lifecycle lifecycle) {
+        super(activity);
+        final SecurityFeatureProvider provider = FeatureFactory.getFactory(activity)
+                .getSecurityFeatureProvider();
+        mActivity = activity;
+        mHost = host;
+        mLockPatternUtils = provider.getLockPatternUtils(activity);
+        mTrustAgentManager = provider.getTrustAgentManager();
+        if (lifecycle != null) {
+            lifecycle.addObserver(this);
+        }
+    }
+
+    @Override
+    public boolean isAvailable() {
+        return true;
+    }
+
+    @Override
+    public String getPreferenceKey() {
+        return PREF_KEY_TRUST_AGENT;
+    }
+
+    @Override
+    public void displayPreference(PreferenceScreen screen) {
+        super.displayPreference(screen);
+        mSecurityCategory = (PreferenceCategory) screen.findPreference(PREF_KEY_SECURITY_CATEGORY);
+    }
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        if (savedInstanceState != null
+                && savedInstanceState.containsKey(TRUST_AGENT_CLICK_INTENT)) {
+            mTrustAgentClickIntent = savedInstanceState.getParcelable(TRUST_AGENT_CLICK_INTENT);
+        }
+    }
+
+    @Override
+    public void onSaveInstanceState(Bundle outState) {
+        if (mTrustAgentClickIntent != null) {
+            outState.putParcelable(TRUST_AGENT_CLICK_INTENT, mTrustAgentClickIntent);
+        }
+    }
+
+    @Override
+    public boolean handlePreferenceTreeClick(Preference preference) {
+        if (!TextUtils.equals(preference.getKey(), getPreferenceKey())) {
+            return super.handlePreferenceTreeClick(preference);
+        }
+        final ChooseLockSettingsHelper helper = new ChooseLockSettingsHelper(mActivity, mHost);
+        mTrustAgentClickIntent = preference.getIntent();
+        boolean confirmationLaunched = helper.launchConfirmationActivity(
+                SecuritySettingsV2.CHANGE_TRUST_AGENT_SETTINGS, preference.getTitle());
+
+        if (!confirmationLaunched && mTrustAgentClickIntent != null) {
+            // If this returns false, it means no password confirmation is required.
+            mHost.startActivity(mTrustAgentClickIntent);
+            mTrustAgentClickIntent = null;
+        }
+        return true;
+    }
+
+    @Override
+    public void onResume() {
+        if (mSecurityCategory == null) {
+            return;
+        }
+        // First remove all old trust agents.
+        while (true) {
+            final Preference oldAgent = mSecurityCategory.findPreference(PREF_KEY_TRUST_AGENT);
+            if (oldAgent == null) {
+                break;
+            } else {
+                mSecurityCategory.removePreference(oldAgent);
+            }
+        }
+        // Then add new ones.
+        final boolean hasSecurity = mLockPatternUtils.isSecure(MY_USER_ID);
+        final List<TrustAgentManager.TrustAgentComponentInfo> agents =
+                mTrustAgentManager.getActiveTrustAgents(mContext, mLockPatternUtils);
+        if (agents == null) {
+            return;
+        }
+        for (TrustAgentManager.TrustAgentComponentInfo agent : agents) {
+            final RestrictedPreference trustAgentPreference =
+                    new RestrictedPreference(mSecurityCategory.getContext());
+            trustAgentPreference.setKey(PREF_KEY_TRUST_AGENT);
+            trustAgentPreference.setTitle(agent.title);
+            trustAgentPreference.setSummary(agent.summary);
+            // Create intent for this preference.
+            trustAgentPreference.setIntent(new Intent(Intent.ACTION_MAIN)
+                    .setComponent(agent.componentName));
+            trustAgentPreference.setDisabledByAdmin(agent.admin);
+            if (!trustAgentPreference.isDisabledByAdmin() && !hasSecurity) {
+                trustAgentPreference.setEnabled(false);
+                trustAgentPreference.setSummary(R.string.disabled_because_no_backup_security);
+            }
+            // Add preference to the settings menu.
+            mSecurityCategory.addPreference(trustAgentPreference);
+        }
+    }
+
+    public void handleActivityResult(int resultCode) {
+        if (resultCode == Activity.RESULT_OK && mTrustAgentClickIntent != null) {
+            mHost.startActivity(mTrustAgentClickIntent);
+            mTrustAgentClickIntent = null;
+        }
+    }
+}
diff --git a/src/com/android/settings/utils/FileSizeFormatter.java b/src/com/android/settings/utils/FileSizeFormatter.java
index c0d360f..e56388a 100644
--- a/src/com/android/settings/utils/FileSizeFormatter.java
+++ b/src/com/android/settings/utils/FileSizeFormatter.java
@@ -16,22 +16,11 @@
 
 package com.android.settings.utils;
 
-import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.Context;
 import android.content.res.Resources;
-import android.icu.text.DecimalFormat;
-import android.icu.text.MeasureFormat;
-import android.icu.text.NumberFormat;
-import android.icu.util.Measure;
-import android.icu.util.MeasureUnit;
 import android.text.BidiFormatter;
-import android.text.TextUtils;
 import android.text.format.Formatter;
-import android.view.View;
-
-import java.math.BigDecimal;
-import java.util.Locale;
 
 /**
  * Utility class to aid in formatting file sizes always with the same unit. This is modified from
@@ -42,61 +31,6 @@
     public static final long MEGABYTE_IN_BYTES = KILOBYTE_IN_BYTES * 1000;
     public static final long GIGABYTE_IN_BYTES = MEGABYTE_IN_BYTES * 1000;
 
-    private static class RoundedBytesResult {
-        public final float value;
-        public final MeasureUnit units;
-        public final int fractionDigits;
-        public final long roundedBytes;
-
-        public RoundedBytesResult(
-                float value, MeasureUnit units, int fractionDigits, long roundedBytes) {
-            this.value = value;
-            this.units = units;
-            this.fractionDigits = fractionDigits;
-            this.roundedBytes = roundedBytes;
-        }
-    }
-
-    private static Locale localeFromContext(@NonNull Context context) {
-        return context.getResources().getConfiguration().locale;
-    }
-
-    private static String bidiWrap(@NonNull Context context, String source) {
-        final Locale locale = localeFromContext(context);
-        if (TextUtils.getLayoutDirectionFromLocale(locale) == View.LAYOUT_DIRECTION_RTL) {
-            return BidiFormatter.getInstance(true /* RTL*/).unicodeWrap(source);
-        } else {
-            return source;
-        }
-    }
-
-    private static NumberFormat getNumberFormatter(Locale locale, int fractionDigits) {
-        final NumberFormat numberFormatter = NumberFormat.getInstance(locale);
-        numberFormatter.setMinimumFractionDigits(fractionDigits);
-        numberFormatter.setMaximumFractionDigits(fractionDigits);
-        numberFormatter.setGroupingUsed(false);
-        if (numberFormatter instanceof DecimalFormat) {
-            // We do this only for DecimalFormat, since in the general NumberFormat case, calling
-            // setRoundingMode may throw an exception.
-            numberFormatter.setRoundingMode(BigDecimal.ROUND_HALF_UP);
-        }
-        return numberFormatter;
-    }
-
-    private static String formatMeasureShort(Locale locale, NumberFormat numberFormatter,
-            float value, MeasureUnit units) {
-        final MeasureFormat measureFormatter = MeasureFormat.getInstance(
-                locale, MeasureFormat.FormatWidth.SHORT, numberFormatter);
-        return measureFormatter.format(new Measure(value, units));
-    }
-
-    private static String formatRoundedBytesResult(
-            @NonNull Context context, @NonNull RoundedBytesResult input) {
-        final Locale locale = localeFromContext(context);
-        final NumberFormat numberFormatter = getNumberFormatter(locale, input.fractionDigits);
-        return formatMeasureShort(locale, numberFormatter, input.value, input.units);
-    }
-
     /**
      * Formats a content size to be in the form of bytes, kilobytes, megabytes, etc.
      *
@@ -113,17 +47,23 @@
      *
      * @param context Context to use to load the localized units
      * @param sizeBytes size value to be formatted, in bytes
-     * @param unit The unit used for formatting.
-     * @param mult Amount of bytes in the unit.
-     * @return formatted string with the number
+     * @param suffix String id for the unit suffix.
+     * @param mult Amount of bytes in the unit. * @return formatted string with the number
      */
     public static String formatFileSize(
-            @Nullable Context context, long sizeBytes, MeasureUnit unit, long mult) {
+            @Nullable Context context, long sizeBytes, int suffix, long mult) {
         if (context == null) {
             return "";
         }
-        final RoundedBytesResult res = formatBytes(sizeBytes, unit, mult);
-        return bidiWrap(context, formatRoundedBytesResult(context, res));
+        final Formatter.BytesResult res =
+                formatBytes(context.getResources(), sizeBytes, suffix, mult);
+        return BidiFormatter.getInstance()
+                .unicodeWrap(context.getString(getFileSizeSuffix(context), res.value, res.units));
+    }
+
+    private static int getFileSizeSuffix(Context context) {
+        final Resources res = context.getResources();
+        return res.getIdentifier("fileSizeSuffix", "string", "android");
     }
 
     /**
@@ -136,8 +76,8 @@
      * @param suffix String id for the unit suffix.
      * @param mult Amount of bytes in the unit.
      */
-    private static RoundedBytesResult formatBytes(
-            long sizeBytes, MeasureUnit unit, long mult) {
+    private static Formatter.BytesResult formatBytes(
+            Resources res, long sizeBytes, int suffix, long mult) {
         final boolean isNegative = (sizeBytes < 0);
         float result = isNegative ? -sizeBytes : sizeBytes;
         result = result / mult;
@@ -145,29 +85,32 @@
         // compute the rounded value. String.format("%f", 0.1) might not return "0.1" due to
         // floating point errors.
         final int roundFactor;
-        final int roundDigits;
+        final String roundFormat;
         if (mult == 1) {
             roundFactor = 1;
-            roundDigits = 0;
+            roundFormat = "%.0f";
         } else if (result < 1) {
             roundFactor = 100;
-            roundDigits = 2;
+            roundFormat = "%.2f";
         } else if (result < 10) {
             roundFactor = 10;
-            roundDigits = 1;
+            roundFormat = "%.1f";
         } else { // 10 <= result < 100
             roundFactor = 1;
-            roundDigits = 0;
+            roundFormat = "%.0f";
         }
 
         if (isNegative) {
             result = -result;
         }
+        final String roundedString = String.format(roundFormat, result);
 
         // Note this might overflow if abs(result) >= Long.MAX_VALUE / 100, but that's like 80PB so
         // it's okay (for now)...
         final long roundedBytes = (((long) Math.round(result * roundFactor)) * mult / roundFactor);
 
-        return new RoundedBytesResult(result, unit, roundDigits, roundedBytes);
+        final String units = res.getString(suffix);
+
+        return new Formatter.BytesResult(roundedString, units, roundedBytes);
     }
 }
diff --git a/tests/robotests/src/com/android/settings/dashboard/DashboardFragmentTest.java b/tests/robotests/src/com/android/settings/dashboard/DashboardFragmentTest.java
index c330340..6c663ab 100644
--- a/tests/robotests/src/com/android/settings/dashboard/DashboardFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/dashboard/DashboardFragmentTest.java
@@ -91,6 +91,19 @@
     }
 
     @Test
+    public void testPreferenceControllerSetter_shouldAddAndNotReplace() {
+        final TestPreferenceController controller1 = new TestPreferenceController(mContext);
+        mTestFragment.addPreferenceController(controller1);
+        final TestPreferenceController controller2 = new TestPreferenceController(mContext);
+        mTestFragment.addPreferenceController(controller2);
+
+        final TestPreferenceController retrievedController = mTestFragment.getPreferenceController
+                (TestPreferenceController.class);
+
+        assertThat(controller1).isSameAs(retrievedController);
+    }
+
+    @Test
     public void displayTilesAsPreference_shouldAddTilesWithIntent() {
         when(mFakeFeatureFactory.dashboardFeatureProvider
                 .getTilesForCategory(nullable(String.class)))
@@ -146,6 +159,23 @@
     }
 
     @Test
+    public void updateState_doesNotSkipControllersOfSameClass() {
+        final AbstractPreferenceController mockController1 =
+                mock(AbstractPreferenceController.class);
+        final AbstractPreferenceController mockController2 =
+                mock(AbstractPreferenceController.class);
+        mTestFragment.addPreferenceController(mockController1);
+        mTestFragment.addPreferenceController(mockController2);
+        when(mockController1.isAvailable()).thenReturn(true);
+        when(mockController2.isAvailable()).thenReturn(true);
+
+        mTestFragment.updatePreferenceStates();
+
+        verify(mockController1).getPreferenceKey();
+        verify(mockController2).getPreferenceKey();
+    }
+
+    @Test
     public void tintTileIcon_hasMetadata_shouldReturnIconTintableMetadata() {
         final Tile tile = new Tile();
         tile.icon = mock(Icon.class);
diff --git a/tests/robotests/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceControllerTest.java
index b20823b..1a3139d 100644
--- a/tests/robotests/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceControllerTest.java
@@ -92,6 +92,8 @@
     @Before
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
+        SettingsShadowResources.overrideResource("android:string/fileSizeSuffix", "%1$s %2$s");
+        SettingsShadowResources.overrideResource("android:string/gigabyteShort", "GB");
         when(mFragment.getActivity()).thenReturn(mActivity);
         when(mFragment.getFragmentManager()).thenReturn(mFragmentManager);
         when(mFragmentManager.beginTransaction()).thenReturn(mFragmentTransaction);
diff --git a/tests/robotests/src/com/android/settings/security/screenlock/ScreenLockSettingsTest.java b/tests/robotests/src/com/android/settings/security/screenlock/ScreenLockSettingsTest.java
index 4213fc5..374b7ec 100644
--- a/tests/robotests/src/com/android/settings/security/screenlock/ScreenLockSettingsTest.java
+++ b/tests/robotests/src/com/android/settings/security/screenlock/ScreenLockSettingsTest.java
@@ -33,6 +33,8 @@
 import org.robolectric.annotation.Config;
 import org.robolectric.util.ReflectionHelpers;
 
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Map;
 
 @RunWith(SettingsRobolectricTestRunner.class)
@@ -55,10 +57,12 @@
 
     @Test
     public void onOwnerInfoUpdated_shouldUpdateOwnerInfoController() {
-        final Map<Class, AbstractPreferenceController> preferenceControllers =
+        final Map<Class, List<AbstractPreferenceController>> preferenceControllers =
                 ReflectionHelpers.getField(mSettings, "mPreferenceControllers");
         final OwnerInfoPreferenceController controller = mock(OwnerInfoPreferenceController.class);
-        preferenceControllers.put(OwnerInfoPreferenceController.class, controller);
+        List<AbstractPreferenceController> controllerList = new ArrayList<>();
+        controllerList.add(controller);
+        preferenceControllers.put(OwnerInfoPreferenceController.class, controllerList);
 
         mSettings.onOwnerInfoUpdated();
 
diff --git a/tests/robotests/src/com/android/settings/security/trustagent/TrustAgentListPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/security/trustagent/TrustAgentListPreferenceControllerTest.java
new file mode 100644
index 0000000..a97780b
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/security/trustagent/TrustAgentListPreferenceControllerTest.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2018 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.security.trustagent;
+
+
+import static com.android.settings.security.trustagent.TrustAgentListPreferenceController
+        .PREF_KEY_SECURITY_CATEGORY;
+import static com.android.settings.security.trustagent.TrustAgentListPreferenceController
+        .PREF_KEY_TRUST_AGENT;
+import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.Activity;
+import android.content.ComponentName;
+import android.content.Context;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.PreferenceCategory;
+import android.support.v7.preference.PreferenceScreen;
+
+import com.android.internal.widget.LockPatternUtils;
+import com.android.settings.TestConfig;
+import com.android.settings.security.SecuritySettingsV2;
+import com.android.settings.testutils.FakeFeatureFactory;
+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.Robolectric;
+import org.robolectric.annotation.Config;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class TrustAgentListPreferenceControllerTest {
+
+    @Mock
+    private TrustAgentManager mTrustAgentManager;
+    @Mock
+    private LockPatternUtils mLockPatternUtils;
+    @Mock
+    private PreferenceScreen mScreen;
+    @Mock
+    private PreferenceCategory mCategory;
+    @Mock
+    private SecuritySettingsV2 mFragment;
+
+    private Lifecycle mLifecycle;
+    private FakeFeatureFactory mFeatureFactory;
+    private Activity mActivity;
+
+    private TrustAgentListPreferenceController mController;
+
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mActivity = Robolectric.buildActivity(Activity.class).get();
+        mLifecycle = new Lifecycle(() -> mLifecycle);
+        mFeatureFactory = FakeFeatureFactory.setupForTest();
+        when(mFeatureFactory.securityFeatureProvider.getLockPatternUtils(any(Context.class)))
+                .thenReturn(mLockPatternUtils);
+        when(mFeatureFactory.securityFeatureProvider.getTrustAgentManager())
+                .thenReturn(mTrustAgentManager);
+        when(mCategory.getKey()).thenReturn(PREF_KEY_SECURITY_CATEGORY);
+        when(mCategory.getContext()).thenReturn(mActivity);
+        when(mScreen.findPreference(PREF_KEY_SECURITY_CATEGORY))
+                .thenReturn(mCategory);
+        mController = new TrustAgentListPreferenceController(mActivity, mFragment, mLifecycle);
+    }
+
+    @Test
+    public void testConstants() {
+        assertThat(mController.isAvailable()).isTrue();
+        assertThat(mController.getPreferenceKey()).isEqualTo(PREF_KEY_TRUST_AGENT);
+    }
+
+    @Test
+    public void onResume_shouldClearOldAgents() {
+        final Preference oldAgent = new Preference(mActivity);
+        oldAgent.setKey(PREF_KEY_TRUST_AGENT);
+        when(mCategory.findPreference(PREF_KEY_TRUST_AGENT))
+                .thenReturn(oldAgent)
+                .thenReturn(null);
+
+        mController.displayPreference(mScreen);
+        mController.onResume();
+
+        verify(mCategory).removePreference(oldAgent);
+    }
+
+    @Test
+    public void onResume_shouldAddNewAgents() {
+        final List<TrustAgentManager.TrustAgentComponentInfo> agents = new ArrayList<>();
+        final TrustAgentManager.TrustAgentComponentInfo agent = mock(
+                TrustAgentManager.TrustAgentComponentInfo.class);
+        agent.title = "Test_title";
+        agent.summary = "test summary";
+        agent.componentName = new ComponentName("pkg", "agent");
+        agent.admin = null;
+        agents.add(agent);
+        when(mTrustAgentManager.getActiveTrustAgents(mActivity, mLockPatternUtils))
+                .thenReturn(agents);
+
+        mController.displayPreference(mScreen);
+        mController.onResume();
+
+        verify(mCategory).addPreference(any(Preference.class));
+    }
+}
diff --git a/tests/unit/README b/tests/unit/README
index 2544ea5..5184b07 100644
--- a/tests/unit/README
+++ b/tests/unit/README
@@ -1,8 +1,8 @@
 To build the tests you can use the following command at the root of your android source tree
-$ make -j SettingsUnitTests
+$ make SettingsUnitTests
 
 The test apk then needs to be installed onto your test device via for example
-$ adb install -r ${ANDROID_PRODUCT_OUT}/data/app/SettingsUnitTests/SettingsUnitTests.apk
+$ adb install -r out/target/product/shamu/data/app/SettingsUnitTests/SettingsUnitTests.apk
 
 To run all tests:
 $ adb shell am instrument -w com.android.settings.tests.unit/android.support.test.runner.AndroidJUnitRunner
diff --git a/tests/unit/src/com/android/settings/utils/FileSizeFormatterTest.java b/tests/unit/src/com/android/settings/utils/FileSizeFormatterTest.java
index 41b236c..c5b050a 100644
--- a/tests/unit/src/com/android/settings/utils/FileSizeFormatterTest.java
+++ b/tests/unit/src/com/android/settings/utils/FileSizeFormatterTest.java
@@ -22,7 +22,6 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import android.content.Context;
-import android.icu.util.MeasureUnit;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
@@ -47,7 +46,7 @@
                         FileSizeFormatter.formatFileSize(
                                 mContext,
                                 0 /* size */,
-                                MeasureUnit.GIGABYTE,
+                                com.android.internal.R.string.gigabyteShort,
                                 GIGABYTE_IN_BYTES))
                 .isEqualTo("0.00 GB");
     }
@@ -58,7 +57,7 @@
                         FileSizeFormatter.formatFileSize(
                                 mContext,
                                 MEGABYTE_IN_BYTES * 11 /* size */,
-                                MeasureUnit.GIGABYTE,
+                                com.android.internal.R.string.gigabyteShort,
                                 GIGABYTE_IN_BYTES))
                 .isEqualTo("0.01 GB");
     }
@@ -69,7 +68,7 @@
                         FileSizeFormatter.formatFileSize(
                                 mContext,
                                 MEGABYTE_IN_BYTES * 155 /* size */,
-                                MeasureUnit.GIGABYTE,
+                                com.android.internal.R.string.gigabyteShort,
                                 GIGABYTE_IN_BYTES))
                 .isEqualTo("0.16 GB");
     }
@@ -80,7 +79,7 @@
                         FileSizeFormatter.formatFileSize(
                                 mContext,
                                 MEGABYTE_IN_BYTES * 1551 /* size */,
-                                MeasureUnit.GIGABYTE,
+                                com.android.internal.R.string.gigabyteShort,
                                 GIGABYTE_IN_BYTES))
                 .isEqualTo("1.6 GB");
     }
@@ -92,7 +91,7 @@
                         FileSizeFormatter.formatFileSize(
                                 mContext,
                                 GIGABYTE_IN_BYTES * 15 + MEGABYTE_IN_BYTES * 50 /* size */,
-                                MeasureUnit.GIGABYTE,
+                                com.android.internal.R.string.gigabyteShort,
                                 GIGABYTE_IN_BYTES))
                 .isEqualTo("15 GB");
     }
@@ -103,7 +102,7 @@
                         FileSizeFormatter.formatFileSize(
                                 mContext,
                                 MEGABYTE_IN_BYTES * -155 /* size */,
-                                MeasureUnit.GIGABYTE,
+                                com.android.internal.R.string.gigabyteShort,
                                 GIGABYTE_IN_BYTES))
                 .isEqualTo("-0.16 GB");
     }