Merge "Launch the Gallery app to manage photos from the Storage screen."
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 09ec9c3..ed511ef 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -3121,7 +3121,7 @@
             <meta-data android:name="com.android.settings.category"
                        android:value="com.android.settings.category.ia.homepage" />
             <meta-data android:name="com.android.settings.FRAGMENT_CLASS"
-                       android:value="com.android.settings.deviceinfo.StorageDashboardFragment" />
+                       android:value="com.android.settings.deviceinfo.StorageSettings" />
             <meta-data android:name="com.android.settings.PRIMARY_PROFILE_CONTROLLED"
                        android:value="true" />
         </activity>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 8406f8f..5038177 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -8007,6 +8007,19 @@
     <string name="enterprise_privacy_security_logs">Your most recent security log</string>
     <!-- Label indicating that the date at which the admin last took a particular action was "never" (i.e. the admin never took the action so far). -->
     <string name="enterprise_privacy_never">Never</string>
+    <!-- Label explaining that an always-on VPN was set by the admin for the entire device. [CHAR LIMIT=NONE] -->
+    <string name="enterprise_privacy_always_on_vpn_device">Always-on VPN turned on</string>
+    <!-- Label explaining that an always-on VPN was set by the admin in the personal profile. [CHAR LIMIT=NONE] -->
+    <string name="enterprise_privacy_always_on_vpn_personal">Always-on VPN turned on in your personal profile</string>
+    <!-- Label explaining that an always-on VPN was set by the admin in the work profile. [CHAR LIMIT=NONE] -->
+    <string name="enterprise_privacy_always_on_vpn_work">Always-on VPN turned on in your work profile</string>
+    <!-- Label explaining that a global HTTP proxy was set by the admin. [CHAR LIMIT=NONE] -->
+    <string name="enterprise_privacy_global_http_proxy">Global HTTP proxy set</string>
+    <!-- Label indicating how many apps were installed on the device by the admin. [CHAR LIMIT=NONE] -->
+    <plurals name="enterprise_privacy_number_enterprise_installed_packages">
+        <item quantity="one"><xliff:g id="count">%d</xliff:g> app installed by your admin</item>
+        <item quantity="other"><xliff:g id="count">%d</xliff:g> apps installed by your admin</item>
+    </plurals>
 
     <!-- Preference label for the Photos & Videos storage section. [CHAR LIMIT=50] -->
     <string name="storage_photos_videos">Photos &amp; Videos</string>
diff --git a/res/xml/enterprise_privacy_settings.xml b/res/xml/enterprise_privacy_settings.xml
index e1761e2..9fed938 100644
--- a/res/xml/enterprise_privacy_settings.xml
+++ b/res/xml/enterprise_privacy_settings.xml
@@ -59,6 +59,24 @@
     </PreferenceCategory>
 
     <PreferenceCategory android:title="@string/enterprise_privacy_exposure_changes_category">
+        <com.android.settings.DividerPreference
+                android:key="always_on_vpn_primary_user"
+                settings:allowDividerBelow="true"
+                settings:multiLine="true"/>
+        <com.android.settings.DividerPreference
+                android:key="always_on_vpn_managed_profile"
+                android:title="@string/enterprise_privacy_always_on_vpn_work"
+                settings:allowDividerBelow="true"
+                settings:multiLine="true"/>
+        <com.android.settings.DividerPreference
+                android:key="global_http_proxy"
+                android:title="@string/enterprise_privacy_global_http_proxy"
+                settings:allowDividerBelow="true"
+                settings:multiLine="true"/>
+        <com.android.settings.DividerPreference
+                android:key="number_enterprise_installed_packages"
+                settings:allowDividerBelow="true"
+                settings:multiLine="true"/>
     </PreferenceCategory>
 
     <PreferenceCategory android:title="@string/enterprise_privacy_device_access_category">
diff --git a/res/xml/location_mode.xml b/res/xml/location_mode.xml
index b1b05bb..e6dc067 100644
--- a/res/xml/location_mode.xml
+++ b/res/xml/location_mode.xml
@@ -17,15 +17,15 @@
 <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
         android:title="@string/location_mode_screen_title">
 
-        <com.android.settings.location.RadioButtonPreference
+        <com.android.settings.widget.RadioButtonPreference
             android:key="high_accuracy"
             android:title="@string/location_mode_high_accuracy_title"
             android:summary="@string/location_mode_high_accuracy_description" />
-        <com.android.settings.location.RadioButtonPreference
+        <com.android.settings.widget.RadioButtonPreference
             android:key="battery_saving"
             android:title="@string/location_mode_battery_saving_title"
             android:summary="@string/location_mode_battery_saving_description" />
-        <com.android.settings.location.RadioButtonPreference
+        <com.android.settings.widget.RadioButtonPreference
             android:key="sensors_only"
             android:title="@string/location_mode_sensors_only_title"
             android:summary="@string/location_mode_sensors_only_description" />
diff --git a/res/xml/storage_dashboard_fragment.xml b/res/xml/storage_dashboard_fragment.xml
index 50287c3..f6d6310 100644
--- a/res/xml/storage_dashboard_fragment.xml
+++ b/res/xml/storage_dashboard_fragment.xml
@@ -36,11 +36,11 @@
         android:title="@string/storage_other_apps">
     </com.android.settings.deviceinfo.storage.StorageItemPreferenceAlternate>
     <com.android.settings.deviceinfo.storage.StorageItemPreferenceAlternate
-        android:key="pref_system"
-        android:title="@string/storage_detail_system">
-    </com.android.settings.deviceinfo.storage.StorageItemPreferenceAlternate>
-    <com.android.settings.deviceinfo.storage.StorageItemPreferenceAlternate
         android:key="pref_files"
         android:title="@string/storage_files">
     </com.android.settings.deviceinfo.storage.StorageItemPreferenceAlternate>
+    <com.android.settings.deviceinfo.storage.StorageItemPreferenceAlternate
+        android:key="pref_system"
+        android:title="@string/storage_detail_system">
+    </com.android.settings.deviceinfo.storage.StorageItemPreferenceAlternate>
 </PreferenceScreen>
\ No newline at end of file
diff --git a/src/com/android/settings/accounts/AccountPreferenceController.java b/src/com/android/settings/accounts/AccountPreferenceController.java
index 02610b7..38f6b1a 100644
--- a/src/com/android/settings/accounts/AccountPreferenceController.java
+++ b/src/com/android/settings/accounts/AccountPreferenceController.java
@@ -63,7 +63,6 @@
 import static android.content.Intent.EXTRA_USER;
 import static android.os.UserManager.DISALLOW_MODIFY_ACCOUNTS;
 import static android.os.UserManager.DISALLOW_REMOVE_MANAGED_PROFILE;
-import static android.os.UserManager.DISALLOW_REMOVE_USER;
 import static android.provider.Settings.EXTRA_AUTHORITIES;
 
 public class AccountPreferenceController extends PreferenceController
@@ -405,7 +404,8 @@
     }
 
     private void updateAccountTypes(ProfileData profileData) {
-        if (mParent.getPreferenceManager() == null) {
+        if (mParent.getPreferenceManager() == null
+                || profileData.preferenceGroup.getPreferenceManager() == null) {
             // This could happen if activity is finishing
             return;
         }
diff --git a/src/com/android/settings/applications/ApplicationFeatureProvider.java b/src/com/android/settings/applications/ApplicationFeatureProvider.java
index bb0fd4c..1db33a6 100644
--- a/src/com/android/settings/applications/ApplicationFeatureProvider.java
+++ b/src/com/android/settings/applications/ApplicationFeatureProvider.java
@@ -27,10 +27,20 @@
     AppHeaderController newAppHeaderController(Fragment fragment, View appHeader);
 
     /**
+     * Count all installed packages, irrespective of install reason.
+     */
+    public static final int IGNORE_INSTALL_REASON = -1;
+
+    /**
      * Asynchronously calculates the total number of apps installed on the device, across all users
      * and managed profiles.
+     *
+     * @param installReason Only consider packages with this install reason; may be any install
+     *         reason defined in {@link android.content.pm.PackageManager} or
+     *         {@link #IGNORE_INSTALL_REASON} to count all packages, irrespective of install reason.
+     * @param callback The callback to invoke with the result
      */
-    void calculateNumberOfInstalledApps(NumberOfInstalledAppsCallback callback);
+    void calculateNumberOfInstalledApps(int installReason, NumberOfInstalledAppsCallback callback);
 
     /**
      * Callback that receives the total number of packages installed on the device.
diff --git a/src/com/android/settings/applications/ApplicationFeatureProviderImpl.java b/src/com/android/settings/applications/ApplicationFeatureProviderImpl.java
index a284a0a..902008c 100644
--- a/src/com/android/settings/applications/ApplicationFeatureProviderImpl.java
+++ b/src/com/android/settings/applications/ApplicationFeatureProviderImpl.java
@@ -42,15 +42,16 @@
     }
 
     @Override
-    public void calculateNumberOfInstalledApps(NumberOfInstalledAppsCallback callback) {
-        new AllUserInstalledAppCounter(callback).execute();
+    public void calculateNumberOfInstalledApps(int installReason,
+            NumberOfInstalledAppsCallback callback) {
+        new AllUserInstalledAppCounter(installReason, callback).execute();
     }
 
     private class AllUserInstalledAppCounter extends InstalledAppCounter {
         private NumberOfInstalledAppsCallback mCallback;
 
-        AllUserInstalledAppCounter(NumberOfInstalledAppsCallback callback) {
-            super(mContext, ApplicationFeatureProviderImpl.this.mPm);
+        AllUserInstalledAppCounter(int installReason, NumberOfInstalledAppsCallback callback) {
+            super(mContext, installReason, ApplicationFeatureProviderImpl.this.mPm);
             mCallback = callback;
         }
 
diff --git a/src/com/android/settings/applications/InstalledAppCounter.java b/src/com/android/settings/applications/InstalledAppCounter.java
index 9faef7a..251b0a2 100644
--- a/src/com/android/settings/applications/InstalledAppCounter.java
+++ b/src/com/android/settings/applications/InstalledAppCounter.java
@@ -25,12 +25,24 @@
 
 public abstract class InstalledAppCounter extends AppCounter {
 
-    public InstalledAppCounter(Context context, PackageManagerWrapper packageManager) {
+    private final int mInstallReason;
+    private final PackageManagerWrapper mPackageManager;
+
+    public InstalledAppCounter(Context context, int installReason,
+            PackageManagerWrapper packageManager) {
         super(context, packageManager);
+        mInstallReason = installReason;
+        mPackageManager = packageManager;
     }
 
     @Override
     protected boolean includeInCount(ApplicationInfo info) {
+        final int userId = UserHandle.getUserId(info.uid);
+        if (mInstallReason != ApplicationFeatureProvider.IGNORE_INSTALL_REASON
+                && mPackageManager.getInstallReason(info.packageName,
+                        new UserHandle(userId)) != mInstallReason) {
+            return false;
+        }
         if ((info.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) {
             return true;
         }
@@ -40,7 +52,6 @@
         Intent launchIntent = new Intent(Intent.ACTION_MAIN, null)
                 .addCategory(Intent.CATEGORY_LAUNCHER)
                 .setPackage(info.packageName);
-        int userId = UserHandle.getUserId(info.uid);
         List<ResolveInfo> intents = mPm.queryIntentActivitiesAsUser(
                 launchIntent,
                 PackageManager.GET_DISABLED_COMPONENTS
diff --git a/src/com/android/settings/applications/ManageApplications.java b/src/com/android/settings/applications/ManageApplications.java
index 2b4427e..43bb02a 100644
--- a/src/com/android/settings/applications/ManageApplications.java
+++ b/src/com/android/settings/applications/ManageApplications.java
@@ -1252,7 +1252,7 @@
         @Override
         public void setListening(boolean listening) {
             if (listening) {
-                new InstalledAppCounter(mContext,
+                new InstalledAppCounter(mContext, ApplicationFeatureProvider.IGNORE_INSTALL_REASON,
                         new PackageManagerWrapperImpl(mContext.getPackageManager())) {
                     @Override
                     protected void onCountComplete(int num) {
diff --git a/src/com/android/settings/applications/PackageManagerWrapper.java b/src/com/android/settings/applications/PackageManagerWrapper.java
index 6c783d8..4166ccf 100644
--- a/src/com/android/settings/applications/PackageManagerWrapper.java
+++ b/src/com/android/settings/applications/PackageManagerWrapper.java
@@ -20,6 +20,7 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
+import android.os.UserHandle;
 
 import java.util.List;
 
@@ -56,4 +57,12 @@
      * @see android.content.pm.PackageManager#queryIntentActivitiesAsUser
      */
     List<ResolveInfo> queryIntentActivitiesAsUser(Intent intent, int flags, int userId);
+
+
+    /**
+     * Calls {@code PackageManager.getInstallReason()}.
+     *
+     * @see android.content.pm.PackageManager#getInstallReason
+     */
+    int getInstallReason(String packageName, UserHandle user);
 }
diff --git a/src/com/android/settings/applications/PackageManagerWrapperImpl.java b/src/com/android/settings/applications/PackageManagerWrapperImpl.java
index db1d30a..2427cce 100644
--- a/src/com/android/settings/applications/PackageManagerWrapperImpl.java
+++ b/src/com/android/settings/applications/PackageManagerWrapperImpl.java
@@ -20,6 +20,7 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
+import android.os.UserHandle;
 
 import java.util.List;
 
@@ -50,4 +51,9 @@
     public List<ResolveInfo> queryIntentActivitiesAsUser(Intent intent, int flags, int userId) {
         return mPm.queryIntentActivitiesAsUser(intent, flags, userId);
     }
+
+    @Override
+    public int getInstallReason(String packageName, UserHandle user) {
+        return mPm.getInstallReason(packageName, user);
+    }
 }
diff --git a/src/com/android/settings/core/PreferenceController.java b/src/com/android/settings/core/PreferenceController.java
index 01c998a..002240d 100644
--- a/src/com/android/settings/core/PreferenceController.java
+++ b/src/com/android/settings/core/PreferenceController.java
@@ -16,56 +16,20 @@
 package com.android.settings.core;
 
 import android.content.Context;
-import android.support.v7.preference.Preference;
-import android.support.v7.preference.PreferenceScreen;
 
 import com.android.settings.search.SearchIndexableRaw;
 import com.android.settings.search2.ResultPayload;
+import com.android.settingslib.core.AbstractPreferenceController;
 
 import java.util.List;
 
 /**
  * A controller that manages event for preference.
  */
-public abstract class PreferenceController {
-
-    protected final Context mContext;
+public abstract class PreferenceController extends AbstractPreferenceController {
 
     public PreferenceController(Context context) {
-        mContext = context;
-    }
-
-    /**
-     * Displays preference in this controller.
-     */
-    public void displayPreference(PreferenceScreen screen) {
-        if (isAvailable()) {
-            if (this instanceof Preference.OnPreferenceChangeListener) {
-                final Preference preference = screen.findPreference(getPreferenceKey());
-                preference.setOnPreferenceChangeListener(
-                        (Preference.OnPreferenceChangeListener) this);
-            }
-        } else {
-            removePreference(screen, getPreferenceKey());
-        }
-    }
-
-    /**
-     * Updates the current status of preference (summary, switch state, etc)
-     */
-    public void updateState(Preference preference) {
-
-    }
-
-    /**
-     * Updates non-indexable keys for search provider.
-     *
-     * Called by SearchIndexProvider#getNonIndexableKeys
-     */
-    public void updateNonIndexableKeys(List<String> keys) {
-        if (!isAvailable()) {
-            keys.add(getPreferenceKey());
-        }
+        super(context);
     }
 
     /**
@@ -77,36 +41,6 @@
     }
 
     /**
-     * Returns true if preference is available (should be displayed)
-     */
-    public abstract boolean isAvailable();
-
-    /**
-     * Handles preference tree click
-     *
-     * @param preference the preference being clicked
-     * @return true if click is handled
-     */
-    public boolean handlePreferenceTreeClick(Preference preference) {
-        return false;
-    }
-
-    /**
-     * Returns the key for this preference.
-     */
-    public abstract String getPreferenceKey();
-
-    /**
-     * Removes preference from screen.
-     */
-    protected final void removePreference(PreferenceScreen screen, String key) {
-        Preference pref = screen.findPreference(key);
-        if (pref != null) {
-            screen.removePreference(pref);
-        }
-    }
-
-    /**
      * @return the {@link ResultPayload} corresponding to the search result type for the preference.
      */
     public ResultPayload getResultPayload() {
diff --git a/src/com/android/settings/datetime/AutoTimeZonePreferenceController.java b/src/com/android/settings/datetime/AutoTimeZonePreferenceController.java
index c70289b..b48e535 100644
--- a/src/com/android/settings/datetime/AutoTimeZonePreferenceController.java
+++ b/src/com/android/settings/datetime/AutoTimeZonePreferenceController.java
@@ -67,7 +67,7 @@
     }
 
     public boolean isEnabled() {
-        return Settings.Global.getInt(mContext.getContentResolver(),
+        return isAvailable() && Settings.Global.getInt(mContext.getContentResolver(),
                 Settings.Global.AUTO_TIME_ZONE, 0) > 0;
     }
 }
diff --git a/src/com/android/settings/deviceinfo/StorageDashboardFragment.java b/src/com/android/settings/deviceinfo/StorageDashboardFragment.java
index c9572b3..d05d088 100644
--- a/src/com/android/settings/deviceinfo/StorageDashboardFragment.java
+++ b/src/com/android/settings/deviceinfo/StorageDashboardFragment.java
@@ -62,7 +62,8 @@
 
         // Initialize the storage sizes that we can quickly calc.
         StorageManager sm = context.getSystemService(StorageManager.class);
-        mVolume = sm.findVolumeById(VolumeInfo.ID_PRIVATE_INTERNAL);
+        String volumeId = getArguments().getString(VolumeInfo.EXTRA_VOLUME_ID);
+        mVolume = sm.findVolumeById(volumeId);
         if (!isVolumeValid()) {
             getActivity().finish();
             return;
diff --git a/src/com/android/settings/deviceinfo/StorageSettings.java b/src/com/android/settings/deviceinfo/StorageSettings.java
index 5ee3983..53d4c85 100644
--- a/src/com/android/settings/deviceinfo/StorageSettings.java
+++ b/src/com/android/settings/deviceinfo/StorageSettings.java
@@ -235,9 +235,8 @@
             // Only showing primary internal storage, so just shortcut
             final Bundle args = new Bundle();
             args.putString(VolumeInfo.EXTRA_VOLUME_ID, VolumeInfo.ID_PRIVATE_INTERNAL);
-            PrivateVolumeSettings.setVolumeSize(args, sTotalInternalStorage);
             Intent intent = Utils.onBuildStartFragmentIntent(getActivity(),
-                    PrivateVolumeSettings.class.getName(), args, null, R.string.apps_storage, null,
+                    StorageDashboardFragment.class.getName(), args, null, R.string.apps_storage, null,
                     false);
             intent.putExtra(SettingsDrawerActivity.EXTRA_SHOW_MENU, true);
             getActivity().startActivity(intent);
@@ -280,9 +279,7 @@
             if (vol.getType() == VolumeInfo.TYPE_PRIVATE) {
                 final Bundle args = new Bundle();
                 args.putString(VolumeInfo.EXTRA_VOLUME_ID, vol.getId());
-                PrivateVolumeSettings.setVolumeSize(args, PrivateStorageInfo.getTotalSize(vol,
-                        sTotalInternalStorage));
-                startFragment(this, PrivateVolumeSettings.class.getCanonicalName(),
+                startFragment(this, StorageDashboardFragment.class.getCanonicalName(),
                         -1, 0, args);
                 return true;
 
diff --git a/src/com/android/settings/enterprise/AlwaysOnVpnManagedProfilePreferenceController.java b/src/com/android/settings/enterprise/AlwaysOnVpnManagedProfilePreferenceController.java
new file mode 100644
index 0000000..52625ec
--- /dev/null
+++ b/src/com/android/settings/enterprise/AlwaysOnVpnManagedProfilePreferenceController.java
@@ -0,0 +1,47 @@
+/*
+ * 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.enterprise;
+
+import android.content.Context;
+import android.support.v7.preference.Preference;
+
+import com.android.settings.core.PreferenceController;
+import com.android.settings.overlay.FeatureFactory;
+
+public class AlwaysOnVpnManagedProfilePreferenceController extends PreferenceController {
+
+    private static final String KEY_ALWAYS_ON_VPN_MANAGED_PROFILE = "always_on_vpn_managed_profile";
+    private final EnterprisePrivacyFeatureProvider mFeatureProvider;
+
+    public AlwaysOnVpnManagedProfilePreferenceController(Context context) {
+        super(context);
+        mFeatureProvider = FeatureFactory.getFactory(context)
+                .getEnterprisePrivacyFeatureProvider(context);
+    }
+
+    @Override
+    public void updateState(Preference preference) {
+        preference.setVisible(mFeatureProvider.isAlwaysOnVpnSetInManagedProfile());
+    }
+
+    @Override
+    public boolean isAvailable() {
+        return true;
+    }
+
+    @Override
+    public String getPreferenceKey() {
+        return KEY_ALWAYS_ON_VPN_MANAGED_PROFILE;
+    }
+}
diff --git a/src/com/android/settings/enterprise/AlwaysOnVpnPrimaryUserPreferenceController.java b/src/com/android/settings/enterprise/AlwaysOnVpnPrimaryUserPreferenceController.java
new file mode 100644
index 0000000..c7ffeaf
--- /dev/null
+++ b/src/com/android/settings/enterprise/AlwaysOnVpnPrimaryUserPreferenceController.java
@@ -0,0 +1,51 @@
+/*
+ * 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.enterprise;
+
+import android.content.Context;
+import android.support.v7.preference.Preference;
+
+import com.android.settings.R;
+import com.android.settings.core.PreferenceController;
+import com.android.settings.overlay.FeatureFactory;
+
+public class AlwaysOnVpnPrimaryUserPreferenceController extends PreferenceController {
+
+    private static final String KEY_ALWAYS_ON_VPN_PRIMARY_USER = "always_on_vpn_primary_user";
+    private final EnterprisePrivacyFeatureProvider mFeatureProvider;
+
+    public AlwaysOnVpnPrimaryUserPreferenceController(Context context) {
+        super(context);
+        mFeatureProvider = FeatureFactory.getFactory(context)
+                .getEnterprisePrivacyFeatureProvider(context);
+    }
+
+    @Override
+    public void updateState(Preference preference) {
+        preference.setTitle(mFeatureProvider.isInCompMode()
+                ? R.string.enterprise_privacy_always_on_vpn_personal
+                : R.string.enterprise_privacy_always_on_vpn_device);
+        preference.setVisible(mFeatureProvider.isAlwaysOnVpnSetInPrimaryUser());
+    }
+
+    @Override
+    public boolean isAvailable() {
+        return true;
+    }
+
+    @Override
+    public String getPreferenceKey() {
+        return KEY_ALWAYS_ON_VPN_PRIMARY_USER;
+    }
+}
diff --git a/src/com/android/settings/enterprise/EnterpriseInstalledPackagesPreferenceController.java b/src/com/android/settings/enterprise/EnterpriseInstalledPackagesPreferenceController.java
new file mode 100644
index 0000000..1fbb04a
--- /dev/null
+++ b/src/com/android/settings/enterprise/EnterpriseInstalledPackagesPreferenceController.java
@@ -0,0 +1,63 @@
+/*
+ * 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.enterprise;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.support.v7.preference.Preference;
+
+import com.android.settings.R;
+import com.android.settings.applications.ApplicationFeatureProvider;
+import com.android.settings.core.PreferenceController;
+import com.android.settings.overlay.FeatureFactory;
+
+public class EnterpriseInstalledPackagesPreferenceController extends PreferenceController {
+
+    private static final String KEY_NUMBER_ENTERPRISE_INSTALLED_PACKAGES
+            = "number_enterprise_installed_packages";
+    private final ApplicationFeatureProvider mFeatureProvider;
+
+    public EnterpriseInstalledPackagesPreferenceController(Context context) {
+        super(context);
+        mFeatureProvider = FeatureFactory.getFactory(context)
+                .getApplicationFeatureProvider(context);
+    }
+
+    @Override
+    public void updateState(Preference preference) {
+        mFeatureProvider.calculateNumberOfInstalledApps(
+                PackageManager.INSTALL_REASON_POLICY,
+                (num) -> {
+                    if (num == 0) {
+                        preference.setVisible(false);
+                    } else {
+                        preference.setVisible(true);
+                        preference.setTitle(mContext.getResources().getQuantityString(
+                                R.plurals.enterprise_privacy_number_enterprise_installed_packages,
+                                num, num));
+                    }
+                });
+    }
+
+    @Override
+    public boolean isAvailable() {
+        return true;
+    }
+
+    @Override
+    public String getPreferenceKey() {
+        return KEY_NUMBER_ENTERPRISE_INSTALLED_PACKAGES;
+    }
+}
diff --git a/src/com/android/settings/enterprise/EnterprisePrivacyFeatureProvider.java b/src/com/android/settings/enterprise/EnterprisePrivacyFeatureProvider.java
index efc02d6..43f6903 100644
--- a/src/com/android/settings/enterprise/EnterprisePrivacyFeatureProvider.java
+++ b/src/com/android/settings/enterprise/EnterprisePrivacyFeatureProvider.java
@@ -26,6 +26,12 @@
     boolean hasDeviceOwner();
 
     /**
+     * Returns whether the device is in COMP mode (primary user managed by a Device Owner app and
+     * work profile managed by a Profile Owner app).
+     */
+    boolean isInCompMode();
+
+    /**
      * Returns the time at which the Device Owner last retrieved security logs, or {@code null} if
      * logs were never retrieved by the Device Owner on this device.
      */
@@ -42,4 +48,19 @@
      * logs were never retrieved by the Device Owner on this device.
      */
     Date getLastNetworkLogRetrievalTime();
+
+    /**
+     * Returns whether the Device Owner in the primary user set an always-on VPN.
+     */
+    boolean isAlwaysOnVpnSetInPrimaryUser();
+
+    /**
+     * Returns whether the Profile Owner in the managed profile (if any) set an always-on VPN.
+     */
+    boolean isAlwaysOnVpnSetInManagedProfile();
+
+    /**
+     * Returns whether the Device Owner set a recommended global HTTP proxy.
+     */
+    boolean isGlobalHttpProxySet();
 }
diff --git a/src/com/android/settings/enterprise/EnterprisePrivacyFeatureProviderImpl.java b/src/com/android/settings/enterprise/EnterprisePrivacyFeatureProviderImpl.java
index 2e8b7f6..9fbb083 100644
--- a/src/com/android/settings/enterprise/EnterprisePrivacyFeatureProviderImpl.java
+++ b/src/com/android/settings/enterprise/EnterprisePrivacyFeatureProviderImpl.java
@@ -17,20 +17,32 @@
 package com.android.settings.enterprise;
 
 import android.content.pm.PackageManager;
+import android.content.pm.UserInfo;
+import android.os.UserHandle;
+import android.os.UserManager;
 
 import com.android.settings.applications.PackageManagerWrapper;
+import com.android.settings.vpn2.ConnectivityManagerWrapper;
+import com.android.settings.vpn2.VpnUtils;
 
 import java.util.Date;
+import java.util.List;
 
 public class EnterprisePrivacyFeatureProviderImpl implements EnterprisePrivacyFeatureProvider {
 
     private final DevicePolicyManagerWrapper mDpm;
     private final PackageManagerWrapper mPm;
+    private final UserManager mUm;
+    private final ConnectivityManagerWrapper mCm;
+
+    private static final int MY_USER_ID = UserHandle.myUserId();
 
     public EnterprisePrivacyFeatureProviderImpl(DevicePolicyManagerWrapper dpm,
-            PackageManagerWrapper pm) {
+            PackageManagerWrapper pm, UserManager um, ConnectivityManagerWrapper cm) {
         mDpm = dpm;
         mPm = pm;
+        mUm = um;
+        mCm = cm;
     }
 
     @Override
@@ -41,19 +53,52 @@
         return mDpm.getDeviceOwnerComponentOnAnyUser() != null;
     }
 
+    private int getManagedProfileUserId() {
+        for (final UserInfo userInfo : mUm.getProfiles(MY_USER_ID)) {
+            if (userInfo.isManagedProfile()) {
+                return userInfo.id;
+            }
+        }
+        return -1;
+    }
+
+    @Override
+    public boolean isInCompMode() {
+        return hasDeviceOwner() && getManagedProfileUserId() != -1;
+    }
+
     @Override
     public Date getLastSecurityLogRetrievalTime() {
         final long timestamp = mDpm.getLastSecurityLogRetrievalTime();
         return timestamp < 0 ? null : new Date(timestamp);
     }
 
+    @Override
     public Date getLastBugReportRequestTime() {
         final long timestamp = mDpm.getLastBugReportRequestTime();
         return timestamp < 0 ? null : new Date(timestamp);
     }
 
+    @Override
     public Date getLastNetworkLogRetrievalTime() {
         final long timestamp = mDpm.getLastNetworkLogRetrievalTime();
         return timestamp < 0 ? null : new Date(timestamp);
     }
+
+    @Override
+    public boolean isAlwaysOnVpnSetInPrimaryUser() {
+        return VpnUtils.isAlwaysOnVpnSet(mCm, MY_USER_ID);
+    }
+
+    @Override
+    public boolean isAlwaysOnVpnSetInManagedProfile() {
+        final int managedProfileUserId = getManagedProfileUserId();
+        return managedProfileUserId != -1 &&
+                VpnUtils.isAlwaysOnVpnSet(mCm, managedProfileUserId);
+    }
+
+    @Override
+    public boolean isGlobalHttpProxySet() {
+        return mCm.getGlobalProxy() != null;
+    }
 }
diff --git a/src/com/android/settings/enterprise/EnterprisePrivacySettings.java b/src/com/android/settings/enterprise/EnterprisePrivacySettings.java
index 91d3a65..2cd2862 100644
--- a/src/com/android/settings/enterprise/EnterprisePrivacySettings.java
+++ b/src/com/android/settings/enterprise/EnterprisePrivacySettings.java
@@ -61,6 +61,10 @@
         controllers.add(new NetworkLogsPreferenceController(context));
         controllers.add(new BugReportsPreferenceController(context));
         controllers.add(new SecurityLogsPreferenceController(context));
+        controllers.add(new AlwaysOnVpnPrimaryUserPreferenceController(context));
+        controllers.add(new AlwaysOnVpnManagedProfilePreferenceController(context));
+        controllers.add(new GlobalHttpProxyPreferenceController(context));
+        controllers.add(new EnterpriseInstalledPackagesPreferenceController(context));
         return controllers;
     }
 
diff --git a/src/com/android/settings/enterprise/GlobalHttpProxyPreferenceController.java b/src/com/android/settings/enterprise/GlobalHttpProxyPreferenceController.java
new file mode 100644
index 0000000..e2f2ab9
--- /dev/null
+++ b/src/com/android/settings/enterprise/GlobalHttpProxyPreferenceController.java
@@ -0,0 +1,47 @@
+/*
+ * 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.enterprise;
+
+import android.content.Context;
+import android.support.v7.preference.Preference;
+
+import com.android.settings.core.PreferenceController;
+import com.android.settings.overlay.FeatureFactory;
+
+public class GlobalHttpProxyPreferenceController extends PreferenceController {
+
+    private static final String KEY_GLOBAL_HTTP_PROXY = "global_http_proxy";
+    private final EnterprisePrivacyFeatureProvider mFeatureProvider;
+
+    public GlobalHttpProxyPreferenceController(Context context) {
+        super(context);
+        mFeatureProvider = FeatureFactory.getFactory(context)
+                .getEnterprisePrivacyFeatureProvider(context);
+    }
+
+    @Override
+    public void updateState(Preference preference) {
+        preference.setVisible(mFeatureProvider.isGlobalHttpProxySet());
+    }
+
+    @Override
+    public boolean isAvailable() {
+        return true;
+    }
+
+    @Override
+    public String getPreferenceKey() {
+        return KEY_GLOBAL_HTTP_PROXY;
+    }
+}
diff --git a/src/com/android/settings/enterprise/InstalledPackagesPreferenceController.java b/src/com/android/settings/enterprise/InstalledPackagesPreferenceController.java
index a7afac0..91ac4c2 100644
--- a/src/com/android/settings/enterprise/InstalledPackagesPreferenceController.java
+++ b/src/com/android/settings/enterprise/InstalledPackagesPreferenceController.java
@@ -36,12 +36,10 @@
     @Override
     public void updateState(Preference preference) {
         mFeatureProvider.calculateNumberOfInstalledApps(
-                new ApplicationFeatureProvider.NumberOfInstalledAppsCallback() {
-                    @Override
-                    public void onNumberOfInstalledAppsResult(int num) {
-                        preference.setTitle(mContext.getResources().getQuantityString(
-                                R.plurals.enterprise_privacy_number_installed_packages, num, num));
-                    }
+                ApplicationFeatureProvider.IGNORE_INSTALL_REASON,
+                (num) -> {
+                    preference.setTitle(mContext.getResources().getQuantityString(
+                            R.plurals.enterprise_privacy_number_installed_packages, num, num));
                 });
     }
 
diff --git a/src/com/android/settings/location/LocationMode.java b/src/com/android/settings/location/LocationMode.java
index e50a0d9..4ca098d 100644
--- a/src/com/android/settings/location/LocationMode.java
+++ b/src/com/android/settings/location/LocationMode.java
@@ -21,6 +21,7 @@
 
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.settings.R;
+import com.android.settings.widget.RadioButtonPreference;
 
 /**
  * A page with 3 radio buttons to choose the location mode.
diff --git a/src/com/android/settings/overlay/FeatureFactoryImpl.java b/src/com/android/settings/overlay/FeatureFactoryImpl.java
index eb5d065..060b58c 100644
--- a/src/com/android/settings/overlay/FeatureFactoryImpl.java
+++ b/src/com/android/settings/overlay/FeatureFactoryImpl.java
@@ -18,6 +18,8 @@
 
 import android.app.admin.DevicePolicyManager;
 import android.content.Context;
+import android.net.ConnectivityManager;
+import android.os.UserManager;
 import android.support.annotation.Keep;
 
 import com.android.settings.applications.ApplicationFeatureProvider;
@@ -37,6 +39,7 @@
 import com.android.settings.security.SecurityFeatureProviderImpl;
 import com.android.settings.search2.SearchFeatureProvider;
 import com.android.settings.search2.SearchFeatureProviderImpl;
+import com.android.settings.vpn2.ConnectivityManagerWrapperImpl;
 
 /**
  * {@link FeatureFactory} implementation for AOSP Settings.
@@ -101,7 +104,10 @@
             mEnterprisePrivacyFeatureProvider = new EnterprisePrivacyFeatureProviderImpl(
                     new DevicePolicyManagerWrapperImpl((DevicePolicyManager) context
                             .getSystemService(Context.DEVICE_POLICY_SERVICE)),
-                    new PackageManagerWrapperImpl(context.getPackageManager()));
+                    new PackageManagerWrapperImpl(context.getPackageManager()),
+                    UserManager.get(context),
+                    new ConnectivityManagerWrapperImpl((ConnectivityManager) context
+                            .getSystemService(Context.CONNECTIVITY_SERVICE)));
         }
         return mEnterprisePrivacyFeatureProvider;
     }
diff --git a/src/com/android/settings/vpn2/ConnectivityManagerWrapper.java b/src/com/android/settings/vpn2/ConnectivityManagerWrapper.java
new file mode 100644
index 0000000..9424278
--- /dev/null
+++ b/src/com/android/settings/vpn2/ConnectivityManagerWrapper.java
@@ -0,0 +1,42 @@
+/*
+ * 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.vpn2;
+
+import android.net.ProxyInfo;
+
+/**
+ * This interface replicates a subset of the android.net.ConnectivityManager (CM). The interface
+ * exists so that we can use a thin wrapper around the CM in production code and a mock in tests.
+ * We cannot directly mock or shadow the CM, because some of the methods we rely on are marked as
+ * hidden and are thus invisible to Robolectric.
+ */
+public interface ConnectivityManagerWrapper {
+
+    /**
+     * Calls {@code ConnectivityManager.getAlwaysOnVpnPackageForUser()}.
+     *
+     * @see android.net.ConnectivityManager#getAlwaysOnVpnPackageForUser
+     */
+   String getAlwaysOnVpnPackageForUser(int userId);
+
+    /**
+     * Calls {@code ConnectivityManager.getGlobalProxy()}.
+     *
+     * @see android.net.ConnectivityManager#getGlobalProxy
+     */
+   ProxyInfo getGlobalProxy();
+}
diff --git a/src/com/android/settings/vpn2/ConnectivityManagerWrapperImpl.java b/src/com/android/settings/vpn2/ConnectivityManagerWrapperImpl.java
new file mode 100644
index 0000000..d3c17f2
--- /dev/null
+++ b/src/com/android/settings/vpn2/ConnectivityManagerWrapperImpl.java
@@ -0,0 +1,39 @@
+/*
+ * 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.vpn2;
+
+import android.net.ConnectivityManager;
+import android.net.ProxyInfo;
+
+public class ConnectivityManagerWrapperImpl implements ConnectivityManagerWrapper {
+
+    private final ConnectivityManager mCm;
+
+    public ConnectivityManagerWrapperImpl(ConnectivityManager cm) {
+        mCm = cm;
+    }
+
+    @Override
+    public String getAlwaysOnVpnPackageForUser(int userId) {
+        return mCm.getAlwaysOnVpnPackageForUser(userId);
+    }
+
+    @Override
+    public ProxyInfo getGlobalProxy() {
+        return mCm.getGlobalProxy();
+    }
+}
diff --git a/src/com/android/settings/vpn2/VpnUtils.java b/src/com/android/settings/vpn2/VpnUtils.java
index 07e6c52..c9f971d 100644
--- a/src/com/android/settings/vpn2/VpnUtils.java
+++ b/src/com/android/settings/vpn2/VpnUtils.java
@@ -82,4 +82,8 @@
         return IConnectivityManager.Stub.asInterface(
                 ServiceManager.getService(Context.CONNECTIVITY_SERVICE));
     }
+
+    public static boolean isAlwaysOnVpnSet(ConnectivityManagerWrapper cm, final int userId) {
+        return cm.getAlwaysOnVpnPackageForUser(userId) != null;
+    }
 }
diff --git a/src/com/android/settings/location/RadioButtonPreference.java b/src/com/android/settings/widget/RadioButtonPreference.java
similarity index 83%
rename from src/com/android/settings/location/RadioButtonPreference.java
rename to src/com/android/settings/widget/RadioButtonPreference.java
index 9135266..cf5921e 100644
--- a/src/com/android/settings/location/RadioButtonPreference.java
+++ b/src/com/android/settings/widget/RadioButtonPreference.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 The Android Open Source Project
+ * 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.
@@ -14,9 +14,10 @@
  * limitations under the License.
  */
 
-package com.android.settings.location;
+package com.android.settings.widget;
 
 import android.content.Context;
+import android.support.v4.content.res.TypedArrayUtils;
 import android.support.v7.preference.CheckBoxPreference;
 import android.support.v7.preference.PreferenceViewHolder;
 import android.util.AttributeSet;
@@ -36,7 +37,7 @@
  */
 public class RadioButtonPreference extends CheckBoxPreference {
     public interface OnClickListener {
-        public abstract void onRadioButtonClicked(RadioButtonPreference emiter);
+       void onRadioButtonClicked(RadioButtonPreference emiter);
     }
 
     private OnClickListener mListener = null;
@@ -47,14 +48,16 @@
     }
 
     public RadioButtonPreference(Context context, AttributeSet attrs) {
-        this(context, attrs, com.android.internal.R.attr.checkBoxPreferenceStyle);
+        this(context, attrs, TypedArrayUtils.getAttr(context,
+                android.support.v7.preference.R.attr.preferenceStyle,
+                android.R.attr.preferenceStyle));
     }
 
     public RadioButtonPreference(Context context) {
         this(context, null);
     }
 
-    void setOnClickListener(OnClickListener listener) {
+    public void setOnClickListener(OnClickListener listener) {
         mListener = listener;
     }
 
diff --git a/tests/robotests/src/com/android/settings/accounts/AccountPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accounts/AccountPreferenceControllerTest.java
index 78d6698..87be756 100644
--- a/tests/robotests/src/com/android/settings/accounts/AccountPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/accounts/AccountPreferenceControllerTest.java
@@ -25,6 +25,7 @@
 import android.support.v14.preference.PreferenceFragment;
 import android.support.v7.preference.Preference;
 import android.support.v7.preference.PreferenceGroup;
+import android.support.v7.preference.PreferenceManager;
 import android.support.v7.preference.PreferenceScreen;
 
 import com.android.settings.AccessiblePreferenceCategory;
@@ -324,6 +325,7 @@
         when(mAccountManager.getAuthenticatorTypesAsUser(anyInt())).thenReturn(authDescs);
 
         AccessiblePreferenceCategory preferenceGroup = mock(AccessiblePreferenceCategory.class);
+        when(preferenceGroup.getPreferenceManager()).thenReturn(mock(PreferenceManager.class));
         when(mAccountHelper.createAccessiblePreferenceCategory(any(Context.class))).thenReturn(
             preferenceGroup);
 
diff --git a/tests/robotests/src/com/android/settings/applications/ApplicationFeatureProviderImplTest.java b/tests/robotests/src/com/android/settings/applications/ApplicationFeatureProviderImplTest.java
index 56834db..615d9ad 100644
--- a/tests/robotests/src/com/android/settings/applications/ApplicationFeatureProviderImplTest.java
+++ b/tests/robotests/src/com/android/settings/applications/ApplicationFeatureProviderImplTest.java
@@ -19,6 +19,7 @@
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.content.pm.UserInfo;
+import android.os.UserHandle;
 import android.os.UserManager;
 
 import com.android.settings.SettingsRobolectricTestRunner;
@@ -49,6 +50,9 @@
     private final int MAIN_USER_ID = 0;
     private final int MANAGED_PROFILE_ID = 10;
 
+    private final String APP_1 = "app1";
+    private final String APP_2 = "app2";
+
     private @Mock UserManager mUserManager;
     private @Mock Context mContext;
     private @Mock PackageManagerWrapper mPackageManager;
@@ -78,22 +82,32 @@
                 | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS
                 | PackageManager.MATCH_ANY_USER,
                 MAIN_USER_ID)).thenReturn(Arrays.asList(
-                        ApplicationTestUtils.buildInfo(MAIN_USER_ID, "app1", 0 /* flags */)));
+                        ApplicationTestUtils.buildInfo(MAIN_USER_ID, APP_1, 0 /* flags */)));
+        when(mPackageManager.getInstallReason(APP_1, new UserHandle(MAIN_USER_ID)))
+                .thenReturn(PackageManager.INSTALL_REASON_UNKNOWN);
 
         when(mPackageManager.getInstalledApplicationsAsUser(PackageManager.GET_DISABLED_COMPONENTS
                 | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS,
                 MANAGED_PROFILE_ID)).thenReturn(Arrays.asList(
-                        ApplicationTestUtils.buildInfo(MANAGED_PROFILE_ID, "app2", 0 /* flags */)));
+                        ApplicationTestUtils.buildInfo(MANAGED_PROFILE_ID, APP_2, 0 /* flags */)));
+        when(mPackageManager.getInstallReason(APP_2, new UserHandle(MANAGED_PROFILE_ID)))
+                .thenReturn(PackageManager.INSTALL_REASON_POLICY);
 
-        mProvider.calculateNumberOfInstalledApps(
-                new ApplicationFeatureProvider.NumberOfInstalledAppsCallback() {
-                    @Override
-                    public void onNumberOfInstalledAppsResult(int num) {
-                        numberOfInstalledApps[0] = num;
-                    }
+        // Count all installed apps.
+        mProvider.calculateNumberOfInstalledApps(ApplicationFeatureProvider.IGNORE_INSTALL_REASON,
+                (num) -> {
+                    numberOfInstalledApps[0] = num;
                 });
         ShadowApplication.runBackgroundTasks();
-
         assertThat(numberOfInstalledApps[0]).isEqualTo(2);
+
+        // Count apps with specific install reason only.
+        numberOfInstalledApps[0] = null;
+        mProvider.calculateNumberOfInstalledApps(PackageManager.INSTALL_REASON_POLICY,
+                (num) -> {
+                    numberOfInstalledApps[0] = num;
+                });
+        ShadowApplication.runBackgroundTasks();
+        assertThat(numberOfInstalledApps[0]).isEqualTo(1);
     }
 }
diff --git a/tests/robotests/src/com/android/settings/applications/InstalledAppCounterTest.java b/tests/robotests/src/com/android/settings/applications/InstalledAppCounterTest.java
index b6c84d0..3dc2e9b 100644
--- a/tests/robotests/src/com/android/settings/applications/InstalledAppCounterTest.java
+++ b/tests/robotests/src/com/android/settings/applications/InstalledAppCounterTest.java
@@ -22,6 +22,7 @@
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.content.pm.UserInfo;
+import android.os.UserHandle;
 import android.os.UserManager;
 
 import com.android.settings.SettingsRobolectricTestRunner;
@@ -60,6 +61,13 @@
         shadows = {ShadowUserManager.class})
 public final class InstalledAppCounterTest {
 
+    private final String APP_1 = "app1";
+    private final String APP_2 = "app2";
+    private final String APP_3 = "app3";
+    private final String APP_4 = "app4";
+    private final String APP_5 = "app5";
+    private final String APP_6 = "app6";
+
     private final int MAIN_USER_ID = 0;
     private final int MANAGED_PROFILE_ID = 10;
 
@@ -101,14 +109,25 @@
                 | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS
                 | PackageManager.MATCH_ANY_USER,
                 MAIN_USER_ID)).thenReturn(Arrays.asList(
-                        buildInfo(MAIN_USER_ID, "app1", ApplicationInfo.FLAG_UPDATED_SYSTEM_APP),
-                        buildInfo(MAIN_USER_ID, "app2", 0 /* flags */),
-                        buildInfo(MAIN_USER_ID, "app3", ApplicationInfo.FLAG_SYSTEM),
-                        buildInfo(MAIN_USER_ID, "app4", ApplicationInfo.FLAG_SYSTEM)));
+                        buildInfo(MAIN_USER_ID, APP_1, ApplicationInfo.FLAG_UPDATED_SYSTEM_APP),
+                        buildInfo(MAIN_USER_ID, APP_2, 0 /* flags */),
+                        buildInfo(MAIN_USER_ID, APP_3, ApplicationInfo.FLAG_SYSTEM),
+                        buildInfo(MAIN_USER_ID, APP_4, ApplicationInfo.FLAG_SYSTEM)));
         // For system apps, InstalledAppCounter checks whether they handle the default launcher
         // intent to decide whether to include them in the count of installed apps or not.
-        expectQueryIntentActivities(MAIN_USER_ID, "app3", true /* launchable */);
-        expectQueryIntentActivities(MAIN_USER_ID, "app4", false /* launchable */);
+        expectQueryIntentActivities(MAIN_USER_ID, APP_3, true /* launchable */);
+        expectQueryIntentActivities(MAIN_USER_ID, APP_4, false /* launchable */);
+
+        // app1, app3 and app4 are installed by enterprise policy.
+        final UserHandle mainUser = new UserHandle(MAIN_USER_ID);
+        when(mPackageManager.getInstallReason(APP_1, mainUser))
+                .thenReturn(PackageManager.INSTALL_REASON_POLICY);
+        when(mPackageManager.getInstallReason(APP_2, mainUser))
+                .thenReturn(PackageManager.INSTALL_REASON_UNKNOWN);
+        when(mPackageManager.getInstallReason(APP_3, mainUser))
+                .thenReturn(PackageManager.INSTALL_REASON_POLICY);
+        when(mPackageManager.getInstallReason(APP_4, mainUser))
+                .thenReturn(PackageManager.INSTALL_REASON_POLICY);
 
         // The second user has four apps installed:
         // * app5 is a user-installed app. It should be counted.
@@ -116,12 +135,21 @@
         when(mPackageManager.getInstalledApplicationsAsUser(PackageManager.GET_DISABLED_COMPONENTS
                 | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS,
                 MANAGED_PROFILE_ID)).thenReturn(Arrays.asList(
-                        buildInfo(MANAGED_PROFILE_ID, "app5", 0 /* flags */),
-                        buildInfo(MANAGED_PROFILE_ID, "app6", ApplicationInfo.FLAG_SYSTEM)));
-        expectQueryIntentActivities(MANAGED_PROFILE_ID, "app6", true /* launchable */);
+                        buildInfo(MANAGED_PROFILE_ID, APP_5, 0 /* flags */),
+                        buildInfo(MANAGED_PROFILE_ID, APP_6, ApplicationInfo.FLAG_SYSTEM)));
+        expectQueryIntentActivities(MANAGED_PROFILE_ID, APP_6, true /* launchable */);
 
-        // Count the number of apps installed. Wait for the background task to finish.
-        (new InstalledAppCounterTestable()).execute();
+        // app5 is installed by enterprise policy.
+        final UserHandle managedProfileUser = new UserHandle(MANAGED_PROFILE_ID);
+        when(mPackageManager.getInstallReason(APP_5, managedProfileUser))
+                .thenReturn(PackageManager.INSTALL_REASON_POLICY);
+        when(mPackageManager.getInstallReason(APP_6, managedProfileUser))
+                .thenReturn(PackageManager.INSTALL_REASON_UNKNOWN);
+
+        // Count the number of all apps installed, irrespective of install reason. Wait for the
+        // background task to finish.
+        (new InstalledAppCounterTestable(ApplicationFeatureProvider.IGNORE_INSTALL_REASON))
+                .execute();
         ShadowApplication.runBackgroundTasks();
 
         assertThat(mInstalledAppCount).isEqualTo(5);
@@ -134,11 +162,19 @@
         verify(mPackageManager, atLeast(0)).queryIntentActivitiesAsUser(anyObject(), anyInt(),
                 anyInt());
         verifyNoMoreInteractions(mPackageManager);
+
+        // Count once more, considering apps installed by enterprise policy only. Wait for the
+        // background task to finish.
+        mInstalledAppCount = 0;
+        (new InstalledAppCounterTestable(PackageManager.INSTALL_REASON_POLICY)).execute();
+        ShadowApplication.runBackgroundTasks();
+
+        assertThat(mInstalledAppCount).isEqualTo(3);
     }
 
     private class InstalledAppCounterTestable extends InstalledAppCounter {
-        public InstalledAppCounterTestable() {
-            super(mContext, mPackageManager);
+        public InstalledAppCounterTestable(int installReason) {
+            super(mContext, installReason, mPackageManager);
         }
 
         @Override
diff --git a/tests/robotests/src/com/android/settings/core/PreferenceControllerTest.java b/tests/robotests/src/com/android/settings/core/PreferenceControllerTest.java
deleted file mode 100644
index aaab183..0000000
--- a/tests/robotests/src/com/android/settings/core/PreferenceControllerTest.java
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Copyright (C) 2016 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.core;
-
-import android.content.Context;
-import android.support.v7.preference.Preference;
-import android.support.v7.preference.PreferenceScreen;
-import com.android.settings.SettingsRobolectricTestRunner;
-import com.android.settings.TestConfig;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.robolectric.annotation.Config;
-
-import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-@RunWith(SettingsRobolectricTestRunner.class)
-@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
-public class PreferenceControllerTest {
-
-    @Mock
-    private Context mContext;
-    @Mock
-    private PreferenceScreen mScreen;
-    @Mock
-    private Preference mPreference;
-
-    private TestPrefController mTestPrefController;
-
-    @Before
-    public void setUp() {
-        MockitoAnnotations.initMocks(this);
-        mTestPrefController = new TestPrefController(mContext);
-    }
-
-    @Test
-    public void removeExistingPref_shouldBeRemoved() {
-        when(mScreen.findPreference(TestPrefController.KEY_PREF)).thenReturn(mPreference);
-
-        mTestPrefController.removePreference(mScreen, TestPrefController.KEY_PREF);
-
-        verify(mScreen).removePreference(mPreference);
-    }
-
-    @Test
-    public void removeNonExistingPref_shouldNotRemoveAnything() {
-        mTestPrefController.removePreference(mScreen, TestPrefController.KEY_PREF);
-
-        verify(mScreen, never()).removePreference(any(Preference.class));
-    }
-
-    @Test
-    public void displayPref_ifAvailable() {
-        mTestPrefController.isAvailable = true;
-
-        mTestPrefController.displayPreference(mScreen);
-
-        verify(mScreen, never()).removePreference(any(Preference.class));
-    }
-
-    @Test
-    public void doNotDisplayPref_ifNotAvailable() {
-        when(mScreen.findPreference(TestPrefController.KEY_PREF)).thenReturn(mPreference);
-        mTestPrefController.isAvailable = false;
-
-        mTestPrefController.displayPreference(mScreen);
-
-        verify(mScreen).removePreference(any(Preference.class));
-    }
-
-    private class TestPrefController extends PreferenceController {
-        private static final String KEY_PREF = "test_pref";
-        public boolean isAvailable;
-
-        public TestPrefController(Context context) {
-            super(context);
-        }
-
-        @Override
-        public boolean handlePreferenceTreeClick(Preference preference) {
-            return false;
-        }
-
-        @Override
-        public boolean isAvailable() {
-            return isAvailable;
-        }
-
-        @Override
-        public String getPreferenceKey() {
-            return KEY_PREF;
-        }
-    }
-
-}
diff --git a/tests/robotests/src/com/android/settings/datetime/AutoTimeZonePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/datetime/AutoTimeZonePreferenceControllerTest.java
index cc8d84a..0ac0251 100644
--- a/tests/robotests/src/com/android/settings/datetime/AutoTimeZonePreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/datetime/AutoTimeZonePreferenceControllerTest.java
@@ -55,6 +55,7 @@
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
+        ShadowApplication.getInstance().setSystemService(Context.CONNECTIVITY_SERVICE, mCm);
         mContext = ShadowApplication.getInstance().getApplicationContext();
         mPreference = new Preference(mContext);
         when(mMockContext.getSystemService(Context.CONNECTIVITY_SERVICE)).thenReturn(mCm);
@@ -88,6 +89,24 @@
     }
 
     @Test
+    public void isFromSUW_notEnable() {
+        mController = new AutoTimeZonePreferenceController(
+            mMockContext, null /* callback */, true /* isFromSUW */);
+
+        assertThat(mController.isEnabled()).isFalse();
+    }
+
+    @Test
+    public void isWifiOnly_notEnable() {
+        when(mCm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE)).thenReturn(false);
+
+        mController = new AutoTimeZonePreferenceController(
+            mMockContext, null /* callback */, false /* isFromSUW */);
+
+        assertThat(mController.isEnabled()).isFalse();
+    }
+
+    @Test
     public void testIsEnabled_shouldReadFromSettingsProvider() {
         mController = new AutoTimeZonePreferenceController(
                 mContext, null /* callback */, false /* isFromSUW */);
diff --git a/tests/robotests/src/com/android/settings/enterprise/AlwaysOnVpnManagedProfilePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/enterprise/AlwaysOnVpnManagedProfilePreferenceControllerTest.java
new file mode 100644
index 0000000..a52e049
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/enterprise/AlwaysOnVpnManagedProfilePreferenceControllerTest.java
@@ -0,0 +1,89 @@
+/*
+ * 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.enterprise;
+
+import android.content.Context;
+import android.support.v7.preference.Preference;
+
+import com.android.settings.SettingsRobolectricTestRunner;
+import com.android.settings.TestConfig;
+import com.android.settings.testutils.FakeFeatureFactory;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Answers;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.annotation.Config;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.when;
+
+/**
+ * Tests for {@link AlwaysOnVpnManagedProfilePreferenceController}.
+ */
+@RunWith(SettingsRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public final class AlwaysOnVpnManagedProfilePreferenceControllerTest {
+
+    @Mock(answer = Answers.RETURNS_DEEP_STUBS)
+    private Context mContext;
+    private FakeFeatureFactory mFeatureFactory;
+
+    private AlwaysOnVpnManagedProfilePreferenceController mController;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        FakeFeatureFactory.setupForTest(mContext);
+        mFeatureFactory = (FakeFeatureFactory) FakeFeatureFactory.getFactory(mContext);
+        mController = new AlwaysOnVpnManagedProfilePreferenceController(mContext);
+    }
+
+    @Test
+    public void testUpdateState() {
+        final Preference preference = new Preference(mContext, null, 0, 0);
+        preference.setVisible(true);
+
+        when(mFeatureFactory.enterprisePrivacyFeatureProvider.isAlwaysOnVpnSetInManagedProfile())
+                .thenReturn(false);
+        mController.updateState(preference);
+        assertThat(preference.isVisible()).isFalse();
+
+        when(mFeatureFactory.enterprisePrivacyFeatureProvider.isAlwaysOnVpnSetInManagedProfile())
+                .thenReturn(true);
+        mController.updateState(preference);
+        assertThat(preference.isVisible()).isTrue();
+    }
+
+    @Test
+    public void testIsAvailable() {
+        assertThat(mController.isAvailable()).isTrue();
+    }
+
+    @Test
+    public void testHandlePreferenceTreeClick() {
+        assertThat(mController.handlePreferenceTreeClick(new Preference(mContext, null, 0, 0)))
+                .isFalse();
+    }
+
+    @Test
+    public void testGetPreferenceKey() {
+        assertThat(mController.getPreferenceKey()).isEqualTo("always_on_vpn_managed_profile");
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/enterprise/AlwaysOnVpnPrimaryUserPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/enterprise/AlwaysOnVpnPrimaryUserPreferenceControllerTest.java
new file mode 100644
index 0000000..d504b84
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/enterprise/AlwaysOnVpnPrimaryUserPreferenceControllerTest.java
@@ -0,0 +1,113 @@
+/*
+ * 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.enterprise;
+
+import android.content.Context;
+import com.android.settings.R;
+import android.support.v7.preference.Preference;
+
+import com.android.settings.SettingsRobolectricTestRunner;
+import com.android.settings.TestConfig;
+import com.android.settings.testutils.FakeFeatureFactory;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Answers;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.annotation.Config;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.when;
+
+/**
+ * Tests for {@link AlwaysOnVpnPrimaryUserPreferenceController}.
+ */
+@RunWith(SettingsRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public final class AlwaysOnVpnPrimaryUserPreferenceControllerTest {
+
+    private final String VPN_SET_DEVICE = "VPN set";
+    private final String VPN_SET_PERSONAL = "VPN set in personal profile";
+
+    @Mock(answer = Answers.RETURNS_DEEP_STUBS)
+    private Context mContext;
+    private FakeFeatureFactory mFeatureFactory;
+
+    private AlwaysOnVpnPrimaryUserPreferenceController mController;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        FakeFeatureFactory.setupForTest(mContext);
+        mFeatureFactory = (FakeFeatureFactory) FakeFeatureFactory.getFactory(mContext);
+        mController = new AlwaysOnVpnPrimaryUserPreferenceController(mContext);
+        when(mContext.getString(R.string.enterprise_privacy_always_on_vpn_device))
+                .thenReturn(VPN_SET_DEVICE);
+        when(mContext.getString(R.string.enterprise_privacy_always_on_vpn_personal))
+                .thenReturn(VPN_SET_PERSONAL);
+    }
+
+    @Test
+    public void testUpdateState() {
+        final Preference preference = new Preference(mContext, null, 0, 0);
+        preference.setVisible(true);
+
+        when(mFeatureFactory.enterprisePrivacyFeatureProvider.isInCompMode()).thenReturn(false);
+
+        when(mFeatureFactory.enterprisePrivacyFeatureProvider.isAlwaysOnVpnSetInPrimaryUser())
+                .thenReturn(false);
+        mController.updateState(preference);
+        assertThat(preference.isVisible()).isFalse();
+
+        when(mFeatureFactory.enterprisePrivacyFeatureProvider.isAlwaysOnVpnSetInPrimaryUser())
+                .thenReturn(true);
+        mController.updateState(preference);
+        assertThat(preference.isVisible()).isTrue();
+        assertThat(preference.getTitle()).isEqualTo(VPN_SET_DEVICE);
+
+        when(mFeatureFactory.enterprisePrivacyFeatureProvider.isInCompMode()).thenReturn(true);
+
+        when(mFeatureFactory.enterprisePrivacyFeatureProvider.isAlwaysOnVpnSetInPrimaryUser())
+                .thenReturn(false);
+        mController.updateState(preference);
+        assertThat(preference.isVisible()).isFalse();
+
+        when(mFeatureFactory.enterprisePrivacyFeatureProvider.isAlwaysOnVpnSetInPrimaryUser())
+                .thenReturn(true);
+        mController.updateState(preference);
+        assertThat(preference.isVisible()).isTrue();
+        assertThat(preference.getTitle()).isEqualTo(VPN_SET_PERSONAL);
+    }
+
+    @Test
+    public void testIsAvailable() {
+        assertThat(mController.isAvailable()).isTrue();
+    }
+
+    @Test
+    public void testHandlePreferenceTreeClick() {
+        assertThat(mController.handlePreferenceTreeClick(new Preference(mContext, null, 0, 0)))
+                .isFalse();
+    }
+
+    @Test
+    public void testGetPreferenceKey() {
+        assertThat(mController.getPreferenceKey()).isEqualTo("always_on_vpn_primary_user");
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/enterprise/EnterpriseInstalledPackagesPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/enterprise/EnterpriseInstalledPackagesPreferenceControllerTest.java
new file mode 100644
index 0000000..9a46e14
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/enterprise/EnterpriseInstalledPackagesPreferenceControllerTest.java
@@ -0,0 +1,113 @@
+/*
+ * 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.enterprise;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.support.v7.preference.Preference;
+
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.settings.R;
+import com.android.settings.SettingsRobolectricTestRunner;
+import com.android.settings.TestConfig;
+import com.android.settings.applications.ApplicationFeatureProvider;
+import com.android.settings.testutils.FakeFeatureFactory;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Answers;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+import org.robolectric.annotation.Config;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.anyObject;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.when;
+
+/**
+ * Tests for {@link EnterpriseInstalledPackagesPreferenceController}.
+ */
+@RunWith(SettingsRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public final class EnterpriseInstalledPackagesPreferenceControllerTest {
+
+    @Mock(answer = Answers.RETURNS_DEEP_STUBS)
+    private Context mContext;
+    private FakeFeatureFactory mFeatureFactory;
+
+    private EnterpriseInstalledPackagesPreferenceController mController;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        FakeFeatureFactory.setupForTest(mContext);
+        mFeatureFactory = (FakeFeatureFactory) FakeFeatureFactory.getFactory(mContext);
+        mController = new EnterpriseInstalledPackagesPreferenceController(mContext);
+    }
+
+    private void setNumberOfEnterpriseInstalledPackages(int number) {
+        doAnswer(new Answer() {
+            public Object answer(InvocationOnMock invocation) {
+                ((ApplicationFeatureProvider.NumberOfInstalledAppsCallback)
+                        invocation.getArguments()[1]).onNumberOfInstalledAppsResult(number);
+                return null;
+            }}).when(mFeatureFactory.applicationFeatureProvider)
+                    .calculateNumberOfInstalledApps(eq(PackageManager.INSTALL_REASON_POLICY),
+                            anyObject());
+    }
+
+    @Test
+    public void testUpdateState() {
+        final Preference preference = new Preference(mContext, null, 0, 0);
+        preference.setVisible(true);
+
+        setNumberOfEnterpriseInstalledPackages(20);
+        when(mContext.getResources().getQuantityString(
+                R.plurals.enterprise_privacy_number_enterprise_installed_packages, 20, 20))
+                .thenReturn("20 packages");
+        mController.updateState(preference);
+        assertThat(preference.getTitle()).isEqualTo("20 packages");
+        assertThat(preference.isVisible()).isTrue();
+
+        setNumberOfEnterpriseInstalledPackages(0);
+        mController.updateState(preference);
+        assertThat(preference.isVisible()).isFalse();
+    }
+
+    @Test
+    public void testIsAvailable() {
+        assertThat(mController.isAvailable()).isTrue();
+    }
+
+    @Test
+    public void testHandlePreferenceTreeClick() {
+        assertThat(mController.handlePreferenceTreeClick(new Preference(mContext, null, 0, 0)))
+                .isFalse();
+    }
+
+    @Test
+    public void testGetPreferenceKey() {
+        assertThat(mController.getPreferenceKey())
+                .isEqualTo("number_enterprise_installed_packages");
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/enterprise/EnterprisePrivacyFeatureProviderImplTest.java b/tests/robotests/src/com/android/settings/enterprise/EnterprisePrivacyFeatureProviderImplTest.java
index 9688c12..be1296c 100644
--- a/tests/robotests/src/com/android/settings/enterprise/EnterprisePrivacyFeatureProviderImplTest.java
+++ b/tests/robotests/src/com/android/settings/enterprise/EnterprisePrivacyFeatureProviderImplTest.java
@@ -17,12 +17,16 @@
 package com.android.settings.enterprise;
 
 import android.content.ComponentName;
-import android.content.Context;
 import android.content.pm.PackageManager;
+import android.content.pm.UserInfo;
+import android.net.ProxyInfo;
+import android.os.UserHandle;
+import android.os.UserManager;
 
 import com.android.settings.SettingsRobolectricTestRunner;
 import com.android.settings.TestConfig;
 import com.android.settings.applications.PackageManagerWrapper;
+import com.android.settings.vpn2.ConnectivityManagerWrapper;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -31,7 +35,9 @@
 import org.mockito.MockitoAnnotations;
 import org.robolectric.annotation.Config;
 
+import java.util.ArrayList;
 import java.util.Date;
+import java.util.List;
 
 import static com.google.common.truth.Truth.assertThat;
 import static org.mockito.Mockito.when;
@@ -45,9 +51,16 @@
 
     private final ComponentName DEVICE_OWNER = new ComponentName("dummy", "component");
     private final Date TIMESTAMP = new Date(2011, 11, 11);
+    private final int MY_USER_ID = UserHandle.myUserId();
+    private final int MANAGED_PROFILE_USER_ID = MY_USER_ID + 1;
+    private final String VPN_PACKAGE_ID = "com.example.vpn";
+
+    private List<UserInfo> mProfiles = new ArrayList();
 
     private @Mock DevicePolicyManagerWrapper mDevicePolicyManager;
     private @Mock PackageManagerWrapper mPackageManager;
+    private @Mock UserManager mUserManager;
+    private @Mock ConnectivityManagerWrapper mConnectivityManger;
 
     private EnterprisePrivacyFeatureProvider mProvider;
 
@@ -57,8 +70,11 @@
 
         when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN))
                 .thenReturn(true);
+        when(mUserManager.getProfiles(MY_USER_ID)).thenReturn(mProfiles);
+        mProfiles.add(new UserInfo(MY_USER_ID, "", "", 0 /* flags */));
 
-        mProvider = new EnterprisePrivacyFeatureProviderImpl(mDevicePolicyManager, mPackageManager);
+        mProvider = new EnterprisePrivacyFeatureProviderImpl(mDevicePolicyManager, mPackageManager,
+                mUserManager, mConnectivityManger);
     }
 
     @Test
@@ -71,6 +87,15 @@
     }
 
     @Test
+    public void testIsInCompMode() {
+        when(mDevicePolicyManager.getDeviceOwnerComponentOnAnyUser()).thenReturn(DEVICE_OWNER);
+        assertThat(mProvider.isInCompMode()).isFalse();
+
+        mProfiles.add(new UserInfo(MANAGED_PROFILE_USER_ID, "", "", UserInfo.FLAG_MANAGED_PROFILE));
+        assertThat(mProvider.isInCompMode()).isTrue();
+    }
+
+    @Test
     public void testGetLastSecurityLogRetrievalTime() {
         when(mDevicePolicyManager.getLastSecurityLogRetrievalTime()).thenReturn(-1L);
         assertThat(mProvider.getLastSecurityLogRetrievalTime()).isNull();
@@ -97,4 +122,39 @@
         when(mDevicePolicyManager.getLastNetworkLogRetrievalTime()).thenReturn(TIMESTAMP.getTime());
         assertThat(mProvider.getLastNetworkLogRetrievalTime()).isEqualTo(TIMESTAMP);
     }
+
+    @Test
+    public void testIsAlwaysOnVpnSetInPrimaryUser() {
+        when(mConnectivityManger.getAlwaysOnVpnPackageForUser(MY_USER_ID)).thenReturn(null);
+        assertThat(mProvider.isAlwaysOnVpnSetInPrimaryUser()).isFalse();
+
+        when(mConnectivityManger.getAlwaysOnVpnPackageForUser(MY_USER_ID))
+                .thenReturn(VPN_PACKAGE_ID);
+        assertThat(mProvider.isAlwaysOnVpnSetInPrimaryUser()).isTrue();
+    }
+
+    @Test
+    public void testIsAlwaysOnVpnSetInManagedProfileProfile() {
+        assertThat(mProvider.isAlwaysOnVpnSetInManagedProfile()).isFalse();
+
+        mProfiles.add(new UserInfo(MANAGED_PROFILE_USER_ID, "", "", UserInfo.FLAG_MANAGED_PROFILE));
+
+        when(mConnectivityManger.getAlwaysOnVpnPackageForUser(MANAGED_PROFILE_USER_ID))
+                .thenReturn(null);
+        assertThat(mProvider.isAlwaysOnVpnSetInManagedProfile()).isFalse();
+
+        when(mConnectivityManger.getAlwaysOnVpnPackageForUser(MANAGED_PROFILE_USER_ID))
+                .thenReturn(VPN_PACKAGE_ID);
+        assertThat(mProvider.isAlwaysOnVpnSetInManagedProfile()).isTrue();
+    }
+
+    @Test
+    public void testIsGlobalHttpProxySet() {
+        when(mConnectivityManger.getGlobalProxy()).thenReturn(null);
+        assertThat(mProvider.isGlobalHttpProxySet()).isFalse();
+
+        when(mConnectivityManger.getGlobalProxy()).thenReturn(
+                ProxyInfo.buildDirectProxy("localhost", 123));
+        assertThat(mProvider.isGlobalHttpProxySet()).isTrue();
+    }
 }
diff --git a/tests/robotests/src/com/android/settings/enterprise/EnterprisePrivacySettingsTest.java b/tests/robotests/src/com/android/settings/enterprise/EnterprisePrivacySettingsTest.java
index f6e18c6..5e4e08f 100644
--- a/tests/robotests/src/com/android/settings/enterprise/EnterprisePrivacySettingsTest.java
+++ b/tests/robotests/src/com/android/settings/enterprise/EnterprisePrivacySettingsTest.java
@@ -73,10 +73,17 @@
         final List<PreferenceController> controllers = mSettings.getPreferenceControllers(
                 ShadowApplication.getInstance().getApplicationContext());
         assertThat(controllers).isNotNull();
-        assertThat(controllers.size()).isEqualTo(4);
+        assertThat(controllers.size()).isEqualTo(8);
         assertThat(controllers.get(0)).isInstanceOf(InstalledPackagesPreferenceController.class);
         assertThat(controllers.get(1)).isInstanceOf(NetworkLogsPreferenceController.class);
         assertThat(controllers.get(2)).isInstanceOf(BugReportsPreferenceController.class);
         assertThat(controllers.get(3)).isInstanceOf(SecurityLogsPreferenceController.class);
+        assertThat(controllers.get(4)).isInstanceOf(
+                AlwaysOnVpnPrimaryUserPreferenceController.class);
+        assertThat(controllers.get(5)).isInstanceOf(
+                AlwaysOnVpnManagedProfilePreferenceController.class);
+        assertThat(controllers.get(6)).isInstanceOf(GlobalHttpProxyPreferenceController.class);
+        assertThat(controllers.get(7)).isInstanceOf(
+                EnterpriseInstalledPackagesPreferenceController.class);
     }
 }
diff --git a/tests/robotests/src/com/android/settings/enterprise/GlobalHttpProxyPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/enterprise/GlobalHttpProxyPreferenceControllerTest.java
new file mode 100644
index 0000000..d505bad
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/enterprise/GlobalHttpProxyPreferenceControllerTest.java
@@ -0,0 +1,88 @@
+/*
+ * 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.enterprise;
+
+import android.content.Context;
+import android.support.v7.preference.Preference;
+
+import com.android.settings.SettingsRobolectricTestRunner;
+import com.android.settings.TestConfig;
+import com.android.settings.testutils.FakeFeatureFactory;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Answers;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.annotation.Config;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.when;
+
+/**
+ * Tests for {@link GlobalHttpProxyPreferenceController}.
+ */
+@RunWith(SettingsRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public final class GlobalHttpProxyPreferenceControllerTest {
+    @Mock(answer = Answers.RETURNS_DEEP_STUBS)
+    private Context mContext;
+    private FakeFeatureFactory mFeatureFactory;
+
+    private GlobalHttpProxyPreferenceController mController;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        FakeFeatureFactory.setupForTest(mContext);
+        mFeatureFactory = (FakeFeatureFactory) FakeFeatureFactory.getFactory(mContext);
+        mController = new GlobalHttpProxyPreferenceController(mContext);
+    }
+
+    @Test
+    public void testUpdateState() {
+        final Preference preference = new Preference(mContext, null, 0, 0);
+        preference.setVisible(true);
+
+        when(mFeatureFactory.enterprisePrivacyFeatureProvider.isGlobalHttpProxySet())
+                .thenReturn(false);
+        mController.updateState(preference);
+        assertThat(preference.isVisible()).isFalse();
+
+        when(mFeatureFactory.enterprisePrivacyFeatureProvider.isGlobalHttpProxySet())
+                .thenReturn(true);
+        mController.updateState(preference);
+        assertThat(preference.isVisible()).isTrue();
+    }
+
+    @Test
+    public void testIsAvailable() {
+        assertThat(mController.isAvailable()).isTrue();
+    }
+
+    @Test
+    public void testHandlePreferenceTreeClick() {
+        assertThat(mController.handlePreferenceTreeClick(new Preference(mContext, null, 0, 0)))
+                .isFalse();
+    }
+
+    @Test
+    public void testGetPreferenceKey() {
+        assertThat(mController.getPreferenceKey()).isEqualTo("global_http_proxy");
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/enterprise/InstalledPackagesPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/enterprise/InstalledPackagesPreferenceControllerTest.java
index 79db853..5a0da66 100644
--- a/tests/robotests/src/com/android/settings/enterprise/InstalledPackagesPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/enterprise/InstalledPackagesPreferenceControllerTest.java
@@ -40,6 +40,7 @@
 import static com.google.common.truth.Truth.assertThat;
 import static org.mockito.Mockito.anyObject;
 import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.eq;
 import static org.mockito.Mockito.when;
 
 /**
@@ -69,10 +70,11 @@
         doAnswer(new Answer() {
             public Object answer(InvocationOnMock invocation) {
                 ((ApplicationFeatureProvider.NumberOfInstalledAppsCallback)
-                        invocation.getArguments()[0]).onNumberOfInstalledAppsResult(20);
+                        invocation.getArguments()[1]).onNumberOfInstalledAppsResult(20);
                 return null;
             }}).when(mFeatureFactory.applicationFeatureProvider)
-                    .calculateNumberOfInstalledApps(anyObject());
+                    .calculateNumberOfInstalledApps(
+                            eq(ApplicationFeatureProvider.IGNORE_INSTALL_REASON), anyObject());
         when(mContext.getResources().getQuantityString(
                 R.plurals.enterprise_privacy_number_installed_packages, 20, 20))
                 .thenReturn("20 packages");
diff --git a/tests/robotests/src/com/android/settings/vpn2/VpnUtilsTest.java b/tests/robotests/src/com/android/settings/vpn2/VpnUtilsTest.java
new file mode 100644
index 0000000..582f9fb
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/vpn2/VpnUtilsTest.java
@@ -0,0 +1,45 @@
+/*
+ * 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.vpn2;
+
+import com.android.settings.SettingsRobolectricTestRunner;
+import com.android.settings.TestConfig;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.annotation.Config;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+/**
+ * Tests for {@link VpnUtils}.
+ */
+@RunWith(SettingsRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public final class VpnUtilsTest {
+    @Test
+    public void testIsAlwaysOnVpnSet() {
+        final ConnectivityManagerWrapper cm = mock(ConnectivityManagerWrapper.class);
+        when(cm.getAlwaysOnVpnPackageForUser(0)).thenReturn("com.example.vpn");
+        assertThat(VpnUtils.isAlwaysOnVpnSet(cm, 0)).isTrue();
+
+        when(cm.getAlwaysOnVpnPackageForUser(0)).thenReturn(null);
+        assertThat(VpnUtils.isAlwaysOnVpnSet(cm, 0)).isFalse();
+    }
+}