Merge "Maintain higher color contrast of labels/controlls on the side of the SeekBar in PreviewPagerPreferenceFragment Bug: 27952877" into nyc-dev
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 2db1223..2eb2760 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -1295,6 +1295,7 @@
         <activity android:name="MonitoringCertInfoActivity"
                 android:label="@string/ssl_ca_cert_dialog_title"
                 android:theme="@style/Transparent"
+                android:excludeFromRecents="true"
                 android:taskAffinity="">
             <intent-filter android:priority="1">
                 <action android:name="com.android.settings.MONITORING_CERT_INFO" />
diff --git a/res/layout/dashboard_category.xml b/res/layout/dashboard_category.xml
index b3500b2..7019a9c 100644
--- a/res/layout/dashboard_category.xml
+++ b/res/layout/dashboard_category.xml
@@ -21,7 +21,8 @@
     android:orientation="vertical"
     android:paddingBottom="8dip"
     android:background="@color/card_background"
-    android:importantForAccessibility="noHideDescendants">
+    android:importantForAccessibility="noHideDescendants"
+    android:elevation="@dimen/dashboard_category_elevation" >
 
     <TextView android:id="@android:id/title"
         android:layout_width="match_parent"
diff --git a/res/layout/dashboard_tile.xml b/res/layout/dashboard_tile.xml
index 983e6ea..2f87909 100644
--- a/res/layout/dashboard_tile.xml
+++ b/res/layout/dashboard_tile.xml
@@ -21,7 +21,8 @@
     android:gravity="center_vertical"
     android:minHeight="@dimen/dashboard_tile_minimum_height"
     android:clickable="true"
-    android:background="@drawable/selectable_card" >
+    android:background="@drawable/selectable_card"
+    android:elevation="@dimen/dashboard_category_elevation" >
 
     <ImageView
         android:id="@android:id/icon"
diff --git a/res/layout/radio_info.xml b/res/layout/radio_info.xml
index c64b68e..834bba2 100644
--- a/res/layout/radio_info.xml
+++ b/res/layout/radio_info.xml
@@ -19,9 +19,11 @@
 -->
 <ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
-    android:layout_height="match_parent" >
+    android:layout_height="match_parent">
 
-    <LinearLayout style="@style/info_layout">
+    <LinearLayout style="@style/info_layout"
+        android:descendantFocusability="beforeDescendants"
+        android:focusableInTouchMode="true">
 
         <!-- IMEI -->
         <LinearLayout style="@style/entry_layout">
diff --git a/res/layout/vpn_dialog.xml b/res/layout/vpn_dialog.xml
index 620b43f..6822e95 100644
--- a/res/layout/vpn_dialog.xml
+++ b/res/layout/vpn_dialog.xml
@@ -119,8 +119,7 @@
         <LinearLayout android:id="@+id/login"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
-                android:orientation="vertical"
-                android:visibility="gone">
+                android:orientation="vertical">
 
             <TextView style="@style/vpn_label" android:text="@string/vpn_username"/>
             <EditText style="@style/vpn_value" android:id="@+id/username"/>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index a875199..a1db172 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -3441,6 +3441,13 @@
         If you turn off notifications for this app, you may miss important alerts and updates.
     </string>
 
+    <!-- Manage applications, individual application info screen, section heading for information about the app installer [CHAR_LIMIT=25] -->
+    <string name="app_install_details_group_title">Store</string>
+    <!-- Manage applications, individual application info screen, title for the option which will trigger application info in it's installer [CHAR_LIMIT=25] -->
+    <string name="app_install_details_title">App details</string>
+    <!-- Manage applications, individual application info screen, summary for the option which will trigger application info in it's installer [CHAR_LIMIT=50] -->
+    <string name="app_install_details_summary">App installed from <xliff:g id="app_store">%1$s</xliff:g></string>
+
     <!-- App Ops Settings --> <skip />
     <!-- [CHAR LIMIT=NONE] App ops settings title, on main settings screen. If clicked, the user is taken to a settings screen for app operations -->
     <string name="app_ops_settings">App ops</string>
@@ -5273,13 +5280,22 @@
     <!-- Button to close the SSL CA cert warning dialog box, meaning the user is done reading.  [CHAR LIMIT=NONE] -->
     <string name="done_button">Done</string>
     <!-- Title of Dialog warning users of SSL monitoring. [CHAR LIMIT=NONE] -->
-    <string name="ssl_ca_cert_dialog_title">Network monitoring</string>
+    <plurals name="ssl_ca_cert_dialog_title">
+        <item quantity="one">Trust or remove certificate</item>
+        <item quantity="other">Trust or remove certificates</item>
+    </plurals>
     <!-- Text of message to show to users whose administrator has installed a SSL CA Cert.  [CHAR LIMIT=NONE] -->
-    <string name="ssl_ca_cert_info_message">This device is managed by:\n<xliff:g id="managing_domain">%s</xliff:g>\n\nYour administrator is capable of monitoring your network activity, including emails, apps, and secure websites.\n\nFor more information, contact your administrator.</string>
+    <plurals name="ssl_ca_cert_info_message">
+        <item quantity="one"><xliff:g id="managing_domain">%s</xliff:g> has installed a certificate authority for your work profile, which may allow them to monitor work network activity, including emails, apps, and secure websites. You can choose to either trust or remove this certificate.\n\nFor more information about this certificate, contact your admin.</item>
+        <item quantity="other"><xliff:g id="managing_domain">%s</xliff:g> has installed certificate authorities for your work profile, which may allow them to monitor work network activity, including emails, apps, and secure websites. You can choose to either trust or remove these certificates.\n\nFor more information about these certificates, contact your admin.</item>
+    </plurals>
     <!-- Text of warning to show to users that have a SSL CA Cert installed.  [CHAR LIMIT=NONE] -->
     <string name="ssl_ca_cert_warning_message">A third party is capable of monitoring your network activity, including emails, apps, and secure websites.\n\nA trusted credential installed on your device is making this possible.</string>
     <!-- Label on button that will take the user to the Trusted Credentials settings page.  [CHAR LIMIT=NONE]-->
-    <string name="ssl_ca_cert_settings_button">Check trusted credentials</string>
+    <plurals name="ssl_ca_cert_settings_button">
+        <item quantity="one">Check certificate</item>
+        <item quantity="other">Check certificates</item>
+    </plurals>
 
     <!-- User settings -->
     <skip/>
diff --git a/src/com/android/settings/ConfirmDeviceCredentialActivity.java b/src/com/android/settings/ConfirmDeviceCredentialActivity.java
index 16d0685..d71ba9b 100644
--- a/src/com/android/settings/ConfirmDeviceCredentialActivity.java
+++ b/src/com/android/settings/ConfirmDeviceCredentialActivity.java
@@ -95,6 +95,8 @@
     private String getTitleFromOrganizationName(int userId) {
         DevicePolicyManager dpm = (DevicePolicyManager) getSystemService(
                 Context.DEVICE_POLICY_SERVICE);
-        return (dpm != null) ? dpm.getOrganizationNameForUser(userId) : null;
+        CharSequence organizationNameForUser = (dpm != null)
+                ? dpm.getOrganizationNameForUser(userId) : null;
+        return organizationNameForUser != null ? organizationNameForUser.toString() : null;
     }
 }
diff --git a/src/com/android/settings/CryptKeeper.java b/src/com/android/settings/CryptKeeper.java
index 1b37066..594cd38 100644
--- a/src/com/android/settings/CryptKeeper.java
+++ b/src/com/android/settings/CryptKeeper.java
@@ -799,6 +799,8 @@
         // Asynchronously throw up the IME, since there are issues with requesting it to be shown
         // immediately.
         if (mLockPatternView == null && !mCooldown) {
+            getWindow().setSoftInputMode(
+                                WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
             mHandler.postDelayed(new Runnable() {
                 @Override public void run() {
                     imm.showSoftInputUnchecked(0, null);
diff --git a/src/com/android/settings/DeviceAdminAdd.java b/src/com/android/settings/DeviceAdminAdd.java
index 364700b..ddee6aa 100644
--- a/src/com/android/settings/DeviceAdminAdd.java
+++ b/src/com/android/settings/DeviceAdminAdd.java
@@ -82,6 +82,9 @@
     public static final String EXTRA_DEVICE_ADMIN_PACKAGE_NAME =
             "android.app.extra.DEVICE_ADMIN_PACKAGE_NAME";
 
+    public static final String EXTRA_CALLED_FROM_SUPPORT_DIALOG =
+            "android.app.extra.CALLED_FROM_SUPPORT_DIALOG";
+
     Handler mHandler;
 
     DevicePolicyManager mDPM;
@@ -113,6 +116,8 @@
     int mCurSysAppOpMode;
     int mCurToastAppOpMode;
 
+    boolean mIsCalledFromSupportDialog = false;
+
     @Override
     protected void onCreate(Bundle icicle) {
         super.onCreate(icicle);
@@ -129,6 +134,8 @@
             return;
         }
 
+        mIsCalledFromSupportDialog = getIntent().getBooleanExtra(
+                EXTRA_CALLED_FROM_SUPPORT_DIALOG, false);
 
         String action = getIntent().getAction();
         ComponentName who = (ComponentName)getIntent().getParcelableExtra(
@@ -459,6 +466,18 @@
     }
 
     @Override
+    protected void onUserLeaveHint() {
+        super.onUserLeaveHint();
+        // In case this is triggered from support dialog, finish this activity once the user leaves
+        // so that this won't appear as a background next time support dialog is triggered. This
+        // is because the support dialog activity and this belong to the same task and we can't
+        // start this in new activity since we need to know the calling package in this activity.
+        if (mIsCalledFromSupportDialog) {
+            finish();
+        }
+    }
+
+    @Override
     protected Dialog onCreateDialog(int id, Bundle args) {
         switch (id) {
             case DIALOG_WARNING: {
@@ -539,7 +558,7 @@
                     mActionButton.setText(R.string.remove_device_admin);
                 }
             }
-            String supportMessage = mDPM.getLongSupportMessageForUser(
+            CharSequence supportMessage = mDPM.getLongSupportMessageForUser(
                     mDeviceAdmin.getComponent(), UserHandle.myUserId());
             if (!TextUtils.isEmpty(supportMessage)) {
                 mSupportMessage.setText(supportMessage);
diff --git a/src/com/android/settings/MonitoringCertInfoActivity.java b/src/com/android/settings/MonitoringCertInfoActivity.java
index 9dd83f5..cfa8e6f 100644
--- a/src/com/android/settings/MonitoringCertInfoActivity.java
+++ b/src/com/android/settings/MonitoringCertInfoActivity.java
@@ -18,78 +18,65 @@
 
 import android.app.Activity;
 import android.app.AlertDialog;
-import android.app.Dialog;
 import android.app.admin.DevicePolicyManager;
-import android.content.Context;
 import android.content.DialogInterface;
 import android.content.DialogInterface.OnClickListener;
+import android.content.DialogInterface.OnDismissListener;
 import android.content.Intent;
 import android.os.Bundle;
-import android.os.RemoteException;
-import android.view.WindowManager;
-import android.view.WindowManagerGlobal;
+import android.os.UserHandle;
+import android.provider.Settings;
 
 /**
  * Activity that shows a dialog explaining that a CA cert is allowing someone to monitor network
- * traffic.
+ * traffic. This activity should be launched for the user into which the CA cert is installed.
  */
-public class MonitoringCertInfoActivity extends Activity implements OnClickListener {
-
-    private boolean hasDeviceOwner = false;
+public class MonitoringCertInfoActivity extends Activity implements OnClickListener,
+        OnDismissListener {
 
     @Override
     protected void onCreate(Bundle savedStates) {
         super.onCreate(savedStates);
 
-        DevicePolicyManager dpm =
-                (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);
+        DevicePolicyManager dpm = getSystemService(DevicePolicyManager.class);
+        final int numberOfCertificates = getIntent().getIntExtra(
+                Settings.EXTRA_NUMBER_OF_CERTIFICATES, 1);
 
         final AlertDialog.Builder builder = new AlertDialog.Builder(this);
-        builder.setTitle(R.string.ssl_ca_cert_dialog_title);
+        builder.setTitle(getResources().getQuantityText(R.plurals.ssl_ca_cert_dialog_title,
+                numberOfCertificates));
         builder.setCancelable(true);
-        // TODO See b/25772443
-        hasDeviceOwner = dpm.getDeviceOwnerComponentOnCallingUser() != null;
-        int buttonLabel;
-        if (hasDeviceOwner) {
-            // Institutional case.  Show informational message.
-            String message = this.getResources().getString(R.string.ssl_ca_cert_info_message,
-                    dpm.getDeviceOwnerNameOnAnyUser());
-            builder.setMessage(message);
-            buttonLabel = R.string.done_button;
-        } else {
+        builder.setPositiveButton(getResources().getQuantityText(
+                R.plurals.ssl_ca_cert_settings_button, numberOfCertificates) , this);
+        builder.setNeutralButton(R.string.cancel, null);
+        builder.setOnDismissListener(this);
+
+        if (dpm.getProfileOwner() != null) {
+            builder.setMessage(getResources().getQuantityString(R.plurals.ssl_ca_cert_info_message,
+                    numberOfCertificates, dpm.getProfileOwnerName()));
+        } else if (dpm.getDeviceOwnerComponentOnCallingUser() != null) {
+            builder.setMessage(getResources().getQuantityString(R.plurals.ssl_ca_cert_info_message,
+                    numberOfCertificates, dpm.getDeviceOwnerNameOnAnyUser()));
+        } else  {
             // Consumer case.  Show scary warning.
             builder.setIcon(android.R.drawable.stat_notify_error);
             builder.setMessage(R.string.ssl_ca_cert_warning_message);
-            buttonLabel = R.string.ssl_ca_cert_settings_button;
         }
 
-        builder.setPositiveButton(buttonLabel, this);
-
-        final Dialog dialog = builder.create();
-        dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
-        try {
-            WindowManagerGlobal.getWindowManagerService().dismissKeyguard();
-        } catch (RemoteException e) {
-        }
-        dialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
-            @Override public void onCancel(DialogInterface dialog) {
-                finish();
-            }
-        });
-
-        dialog.show();
+        builder.show();
     }
 
     @Override
     public void onClick(DialogInterface dialog, int which) {
-        if (hasDeviceOwner) {
-            finish();
-        } else {
-            Intent intent =
-                    new Intent(android.provider.Settings.ACTION_TRUSTED_CREDENTIALS_USER);
-            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
-            startActivity(intent);
-            finish();
-        }
+        Intent intent = new Intent(android.provider.Settings.ACTION_TRUSTED_CREDENTIALS_USER);
+        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
+        intent.putExtra(TrustedCredentialsSettings.ARG_SHOW_NEW_FOR_USER, UserHandle.myUserId());
+        startActivity(intent);
+        finish();
+    }
+
+    @Override
+    public void onDismiss(DialogInterface dialogInterface) {
+        finish();
     }
 }
diff --git a/src/com/android/settings/RadioInfo.java b/src/com/android/settings/RadioInfo.java
index 4a1c887..031a1ae 100644
--- a/src/com/android/settings/RadioInfo.java
+++ b/src/com/android/settings/RadioInfo.java
@@ -302,7 +302,7 @@
                 case EVENT_SET_PREFERRED_TYPE_DONE:
                     ar= (AsyncResult) msg.obj;
                     if (ar.exception != null) {
-                        log("Set preferred network type success.");
+                        log("Set preferred network type failed.");
                     }
                     break;
                 case EVENT_QUERY_SMSC_DONE:
@@ -404,7 +404,7 @@
             oemInfoButton.setEnabled(false);
         }
 
-        mCellInfoRefreshRateIndex = CELL_INFO_LIST_RATE_DISABLED;
+        mCellInfoRefreshRateIndex = 0; //disabled
         mPreferredNetworkTypeResult = mPreferredNetworkLabels.length - 1; //Unknown
 
         //FIXME: Replace with TelephonyManager call
@@ -438,9 +438,14 @@
         mPingHostnameV6.setText(mPingHostnameResultV6);
         mHttpClientTest.setText(mHttpClientTestResult);
 
-        //move these here so that the initial updates in create don't cause values to reset
         cellInfoRefreshRateSpinner.setOnItemSelectedListener(mCellInfoRefreshRateHandler);
+        //set selection after registering listener to force update
+        cellInfoRefreshRateSpinner.setSelection(mCellInfoRefreshRateIndex);
+
+        //set selection before registering to prevent update
+        preferredNetworkType.setSelection(mPreferredNetworkTypeResult, true);
         preferredNetworkType.setOnItemSelectedListener(mPreferredNetworkHandler);
+
         radioPowerOnSwitch.setOnCheckedChangeListener(mRadioPowerOnChangeListener);
         imsVoLteProvisionedSwitch.setOnCheckedChangeListener(mImsVoLteCheckedChangeListener);
 
@@ -457,6 +462,8 @@
                 | PhoneStateListener.LISTEN_SERVICE_STATE
                 | PhoneStateListener.LISTEN_SIGNAL_STRENGTHS
                 | PhoneStateListener.LISTEN_DATA_CONNECTION_REAL_TIME_INFO);
+
+        smsc.clearFocus();
     }
 
     @Override
@@ -466,6 +473,7 @@
         log("onPause: unregister phone & data intents");
 
         mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_NONE);
+        phone.setCellInfoListRate(CELL_INFO_LIST_RATE_DISABLED);
     }
 
     private void restoreFromBundle(Bundle b) {
@@ -485,8 +493,6 @@
                                                mPreferredNetworkLabels.length - 1);
 
         mCellInfoRefreshRateIndex = b.getInt("mCellInfoRefreshRateIndex", 0);
-
-        cellInfoRefreshRateSpinner.setSelection(mCellInfoRefreshRateIndex);
     }
 
     @Override
@@ -496,7 +502,6 @@
         outState.putString("mHttpClientTestResult", mHttpClientTestResult);
 
         outState.putInt("mPreferredNetworkTypeResult", mPreferredNetworkTypeResult);
-
         outState.putInt("mCellInfoRefreshRateIndex", mCellInfoRefreshRateIndex);
 
     }
diff --git a/src/com/android/settings/SecuritySettings.java b/src/com/android/settings/SecuritySettings.java
index bcb677d..049660e 100644
--- a/src/com/android/settings/SecuritySettings.java
+++ b/src/com/android/settings/SecuritySettings.java
@@ -625,6 +625,10 @@
             startFragment(this, "com.android.settings.ChooseLockGeneric$ChooseLockGenericFragment",
                     R.string.lock_settings_picker_title, SET_OR_CHANGE_LOCK_METHOD_REQUEST, null);
         } else if (KEY_UNLOCK_SET_OR_CHANGE_PROFILE.equals(key)) {
+            if (Utils.startQuiteModeDialogIfNecessary(this.getActivity(), mUm,
+                    mProfileChallengeUserId)) {
+                return false;
+            }
             Bundle extras = new Bundle();
             extras.putInt(Intent.EXTRA_USER_ID, mProfileChallengeUserId);
             startFragment(this, "com.android.settings.ChooseLockGeneric$ChooseLockGenericFragment",
@@ -746,8 +750,16 @@
         final String key = preference.getKey();
         final LockPatternUtils lockPatternUtils = mChooseLockSettingsHelper.utils();
         if (KEY_VISIBLE_PATTERN_PROFILE.equals(key)) {
+            if (Utils.startQuiteModeDialogIfNecessary(this.getActivity(), mUm,
+                    mProfileChallengeUserId)) {
+                return false;
+            }
             lockPatternUtils.setVisiblePatternEnabled((Boolean) value, mProfileChallengeUserId);
         } else if (KEY_UNIFICATION.equals(key)) {
+            if (Utils.startQuiteModeDialogIfNecessary(this.getActivity(), mUm,
+                    mProfileChallengeUserId)) {
+                return false;
+            }
             if ((Boolean) value) {
                 final boolean compliantForDevice =
                         (mLockPatternUtils.getKeyguardStoredPasswordQuality(mProfileChallengeUserId)
@@ -1282,17 +1294,15 @@
                                 }
                             }
                     )
-                    .setNegativeButton(R.string.cancel,
-                            new DialogInterface.OnClickListener() {
-                                @Override
-                                public void onClick(DialogInterface dialog, int whichButton) {
-                                    parentFragment.updateUnificationPreference();
-                                    dismiss();
-                                }
-                            }
-                    )
+                    .setNegativeButton(R.string.cancel, null)
                     .create();
         }
+
+        @Override
+        public void onDismiss(DialogInterface dialog) {
+            super.onDismiss(dialog);
+            ((SecuritySettings) getParentFragment()).updateUnificationPreference();
+        }
     }
 
 }
diff --git a/src/com/android/settings/ShowAdminSupportDetailsDialog.java b/src/com/android/settings/ShowAdminSupportDetailsDialog.java
index 2f2379a..fce669c 100644
--- a/src/com/android/settings/ShowAdminSupportDetailsDialog.java
+++ b/src/com/android/settings/ShowAdminSupportDetailsDialog.java
@@ -155,6 +155,7 @@
                             intent.setClass(activity, DeviceAdminAdd.class);
                             intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN,
                                     enforcedAdmin.component);
+                            intent.putExtra(DeviceAdminAdd.EXTRA_CALLED_FROM_SUPPORT_DIALOG, true);
                             // DeviceAdminAdd class may need to run as managed profile.
                             activity.startActivityAsUser(intent,
                                     new UserHandle(enforcedAdmin.userId));
diff --git a/src/com/android/settings/TrustedCredentialsDialogBuilder.java b/src/com/android/settings/TrustedCredentialsDialogBuilder.java
new file mode 100644
index 0000000..22dc936
--- /dev/null
+++ b/src/com/android/settings/TrustedCredentialsDialogBuilder.java
@@ -0,0 +1,342 @@
+/*
+ * 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;
+
+import android.annotation.NonNull;
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.admin.DevicePolicyManager;
+import android.content.DialogInterface;
+import android.net.http.SslCertificate;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.view.View;
+import android.view.animation.AnimationUtils;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.Button;
+import android.widget.LinearLayout;
+import android.widget.Spinner;
+
+import com.android.settings.TrustedCredentialsSettings.CertHolder;
+
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.List;
+
+class TrustedCredentialsDialogBuilder extends AlertDialog.Builder {
+    public interface DelegateInterface {
+        List<X509Certificate> getX509CertsFromCertHolder(CertHolder certHolder);
+        void removeOrInstallCert(CertHolder certHolder);
+    }
+
+    private final DialogEventHandler mDialogEventHandler;
+
+    public TrustedCredentialsDialogBuilder(Activity activity, DelegateInterface delegate) {
+        super(activity);
+        mDialogEventHandler = new DialogEventHandler(activity, delegate);
+
+        initDefaultBuilderParams();
+    }
+
+    public TrustedCredentialsDialogBuilder setCertHolder(CertHolder certHolder) {
+        return setCertHolders(certHolder == null ? new CertHolder[0]
+                : new CertHolder[]{certHolder});
+    }
+
+    public TrustedCredentialsDialogBuilder setCertHolders(@NonNull CertHolder[] certHolders) {
+        mDialogEventHandler.setCertHolders(certHolders);
+        return this;
+    }
+
+    @Override
+    public AlertDialog create() {
+        AlertDialog dialog = super.create();
+        dialog.setOnShowListener(mDialogEventHandler);
+        mDialogEventHandler.setDialog(dialog);
+        return dialog;
+    }
+
+    private void initDefaultBuilderParams() {
+        setTitle(com.android.internal.R.string.ssl_certificate);
+        setView(mDialogEventHandler.mRootContainer);
+
+        // Enable buttons here. The actual labels and listeners are configured in nextOrDismiss
+        setPositiveButton(R.string.trusted_credentials_trust_label, null);
+        setNegativeButton(android.R.string.ok, null);
+    }
+
+    private static class DialogEventHandler implements DialogInterface.OnShowListener,
+            View.OnClickListener  {
+        private static final long OUT_DURATION_MS = 300;
+        private static final long IN_DURATION_MS = 200;
+
+        private final Activity mActivity;
+        private final DevicePolicyManager mDpm;
+        private final UserManager mUserManager;
+        private final DelegateInterface mDelegate;
+        private final LinearLayout mRootContainer;
+
+        private int mCurrentCertIndex = -1;
+        private AlertDialog mDialog;
+        private Button mPositiveButton;
+        private Button mNegativeButton;
+        private boolean mNeedsApproval;
+        private CertHolder[] mCertHolders = new CertHolder[0];
+        private View mCurrentCertLayout = null;
+
+        public DialogEventHandler(Activity activity, DelegateInterface delegate) {
+            mActivity = activity;
+            mDpm = activity.getSystemService(DevicePolicyManager.class);
+            mUserManager = activity.getSystemService(UserManager.class);
+            mDelegate = delegate;
+
+            mRootContainer = new LinearLayout(mActivity);
+            mRootContainer.setOrientation(LinearLayout.VERTICAL);
+        }
+
+        public void setDialog(AlertDialog dialog) {
+            mDialog = dialog;
+        }
+
+        public void setCertHolders(CertHolder[] certHolder) {
+            mCertHolders = certHolder;
+        }
+
+        @Override
+        public void onShow(DialogInterface dialogInterface) {
+            // Config the display content only when the dialog is shown because the
+            // positive/negative buttons don't exist until the dialog is shown
+            nextOrDismiss();
+        }
+
+        @Override
+        public void onClick(View view) {
+            if (view == mPositiveButton) {
+                if (mNeedsApproval) {
+                    onClickTrust();
+                } else {
+                    onClickOk();
+                }
+            } else if (view == mNegativeButton) {
+                onClickRemove();
+            }
+        }
+
+        private void onClickOk() {
+            nextOrDismiss();
+        }
+
+        private void onClickTrust() {
+            CertHolder certHolder = getCurrentCertInfo();
+            mDpm.approveCaCert(certHolder.getAlias(), certHolder.getUserId(), true);
+            nextOrDismiss();
+        }
+
+        private void onClickRemove() {
+            final CertHolder certHolder = getCurrentCertInfo();
+            new AlertDialog.Builder(mActivity)
+                    .setMessage(getButtonConfirmation(certHolder))
+                    .setPositiveButton(android.R.string.yes,
+                            new DialogInterface.OnClickListener() {
+                                @Override
+                                public void onClick(DialogInterface dialog, int id) {
+                                    mDelegate.removeOrInstallCert(certHolder);
+                                    dialog.dismiss();
+                                    nextOrDismiss();
+                                }
+                            })
+                    .setNegativeButton(android.R.string.no, null)
+                    .show();
+        }
+
+        private CertHolder getCurrentCertInfo() {
+            return mCurrentCertIndex < mCertHolders.length ? mCertHolders[mCurrentCertIndex] : null;
+        }
+
+        private void nextOrDismiss() {
+            mCurrentCertIndex++;
+            // find next non-null cert or dismiss
+            while (mCurrentCertIndex < mCertHolders.length && getCurrentCertInfo() == null) {
+                mCurrentCertIndex++;
+            }
+
+            if (mCurrentCertIndex >= mCertHolders.length) {
+                mDialog.dismiss();
+                return;
+            }
+
+            updateViewContainer();
+            updatePositiveButton();
+            updateNegativeButton();
+        }
+
+        private void updatePositiveButton() {
+            final CertHolder certHolder = getCurrentCertInfo();
+            mNeedsApproval = !certHolder.isSystemCert() &&
+                    !mDpm.isCaCertApproved(certHolder.getAlias(), certHolder.getUserId());
+
+            // The ok button is optional. User can still dismiss the dialog by other means.
+            // Display it only when trust button is not displayed, because we want users to
+            // either remove or trust a CA cert when the cert is installed by DPC app.
+            CharSequence displayText = mActivity.getText(mNeedsApproval
+                    ? R.string.trusted_credentials_trust_label
+                    : android.R.string.ok);
+            mPositiveButton = updateButton(DialogInterface.BUTTON_POSITIVE, displayText);
+        }
+
+        private void updateNegativeButton() {
+            final CertHolder certHolder = getCurrentCertInfo();
+            final boolean showRemoveButton = !mUserManager.hasUserRestriction(
+                    UserManager.DISALLOW_CONFIG_CREDENTIALS,
+                    new UserHandle(certHolder.getUserId()));
+            CharSequence displayText = mActivity.getText(getButtonLabel(certHolder));
+            mNegativeButton = updateButton(DialogInterface.BUTTON_NEGATIVE, displayText);
+            mNegativeButton.setVisibility(showRemoveButton ? View.VISIBLE : View.GONE);
+        }
+
+        /**
+         * mDialog.setButton doesn't trigger text refresh since mDialog has been shown.
+         * It's invoked only in case mDialog is refreshed.
+         * setOnClickListener is invoked to avoid dismiss dialog onClick
+         */
+        private Button updateButton(int buttonType, CharSequence displayText) {
+            mDialog.setButton(buttonType, displayText, (DialogInterface.OnClickListener) null);
+            Button button = mDialog.getButton(buttonType);
+            button.setText(displayText);
+            button.setOnClickListener(this);
+            return button;
+        }
+
+
+        private void updateViewContainer() {
+            CertHolder certHolder = getCurrentCertInfo();
+            LinearLayout nextCertLayout = getCertLayout(certHolder);
+
+            // Displaying first cert doesn't require animation
+            if (mCurrentCertLayout == null) {
+                mCurrentCertLayout = nextCertLayout;
+                mRootContainer.addView(mCurrentCertLayout);
+            } else {
+                animateViewTransition(nextCertLayout);
+            }
+        }
+
+        private LinearLayout getCertLayout(final CertHolder certHolder) {
+            final ArrayList<View> views =  new ArrayList<View>();
+            final ArrayList<String> titles = new ArrayList<String>();
+            List<X509Certificate> certificates = mDelegate.getX509CertsFromCertHolder(certHolder);
+            if (certificates != null) {
+                for (X509Certificate certificate : certificates) {
+                    SslCertificate sslCert = new SslCertificate(certificate);
+                    views.add(sslCert.inflateCertificateView(mActivity));
+                    titles.add(sslCert.getIssuedTo().getCName());
+                }
+            }
+
+            ArrayAdapter<String> arrayAdapter = new ArrayAdapter<String>(mActivity,
+                    android.R.layout.simple_spinner_item,
+                    titles);
+            arrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+            Spinner spinner = new Spinner(mActivity);
+            spinner.setAdapter(arrayAdapter);
+            spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
+                @Override
+                public void onItemSelected(AdapterView<?> parent, View view, int position,
+                        long id) {
+                    for (int i = 0; i < views.size(); i++) {
+                        views.get(i).setVisibility(i == position ? View.VISIBLE : View.GONE);
+                    }
+                }
+
+                @Override
+                public void onNothingSelected(AdapterView<?> parent) {
+                }
+            });
+
+            LinearLayout certLayout = new LinearLayout(mActivity);
+            certLayout.setOrientation(LinearLayout.VERTICAL);
+            certLayout.addView(spinner);
+            for (int i = 0; i < views.size(); ++i) {
+                View certificateView = views.get(i);
+                // Show first cert by default
+                certificateView.setVisibility(i == 0 ? View.VISIBLE : View.GONE);
+                certLayout.addView(certificateView);
+            }
+
+            return certLayout;
+        }
+
+        private static int getButtonConfirmation(CertHolder certHolder) {
+            return certHolder.isSystemCert() ? ( certHolder.isDeleted()
+                        ? R.string.trusted_credentials_enable_confirmation
+                        : R.string.trusted_credentials_disable_confirmation )
+                    : R.string.trusted_credentials_remove_confirmation;
+        }
+
+        private static int getButtonLabel(CertHolder certHolder) {
+            return certHolder.isSystemCert() ? ( certHolder.isDeleted()
+                        ? R.string.trusted_credentials_enable_label
+                        : R.string.trusted_credentials_disable_label )
+                    : R.string.trusted_credentials_remove_label;
+        }
+
+        /* Animation code */
+        private void animateViewTransition(final View nextCertView) {
+            animateOldContent(new Runnable() {
+                @Override
+                public void run() {
+                    addAndAnimateNewContent(nextCertView);
+                }
+            });
+        }
+
+        private void animateOldContent(Runnable callback) {
+            // Fade out
+            mCurrentCertLayout.animate()
+                    .alpha(0)
+                    .setDuration(OUT_DURATION_MS)
+                    .setInterpolator(AnimationUtils.loadInterpolator(mActivity,
+                            android.R.interpolator.fast_out_linear_in))
+                    .withEndAction(callback)
+                    .start();
+        }
+
+        private void addAndAnimateNewContent(View nextCertLayout) {
+            mCurrentCertLayout = nextCertLayout;
+            mRootContainer.removeAllViews();
+            mRootContainer.addView(nextCertLayout);
+
+            mRootContainer.addOnLayoutChangeListener( new View.OnLayoutChangeListener() {
+                @Override
+                public void onLayoutChange(View v, int left, int top, int right, int bottom,
+                        int oldLeft, int oldTop, int oldRight, int oldBottom) {
+                    mRootContainer.removeOnLayoutChangeListener(this);
+
+                    // Animate slide in from the right
+                    final int containerWidth = mRootContainer.getWidth();
+                    mCurrentCertLayout.setTranslationX(containerWidth);
+                    mCurrentCertLayout.animate()
+                            .translationX(0)
+                            .setInterpolator(AnimationUtils.loadInterpolator(mActivity,
+                                    android.R.interpolator.linear_out_slow_in))
+                            .setDuration(IN_DURATION_MS)
+                            .start();
+                }
+            });
+        }
+    }
+}
diff --git a/src/com/android/settings/TrustedCredentialsSettings.java b/src/com/android/settings/TrustedCredentialsSettings.java
index 5e0aea7..e371229 100644
--- a/src/com/android/settings/TrustedCredentialsSettings.java
+++ b/src/com/android/settings/TrustedCredentialsSettings.java
@@ -16,8 +16,7 @@
 
 package com.android.settings;
 
-import android.app.AlertDialog;
-import android.app.Dialog;
+import android.annotation.UiThread;
 import android.app.KeyguardManager;
 import android.app.admin.DevicePolicyManager;
 import android.content.BroadcastReceiver;
@@ -41,16 +40,11 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.AdapterView;
-import android.widget.AdapterView.OnItemSelectedListener;
-import android.widget.ArrayAdapter;
 import android.widget.BaseAdapter;
 import android.widget.BaseExpandableListAdapter;
-import android.widget.Button;
 import android.widget.ExpandableListView;
-import android.widget.LinearLayout;
 import android.widget.ListView;
 import android.widget.ProgressBar;
-import android.widget.Spinner;
 import android.widget.Switch;
 import android.widget.TabHost;
 import android.widget.TextView;
@@ -67,12 +61,17 @@
 import java.util.HashMap;
 import java.util.List;
 
-public class TrustedCredentialsSettings extends OptionsMenuFragment {
+public class TrustedCredentialsSettings extends OptionsMenuFragment
+        implements TrustedCredentialsDialogBuilder.DelegateInterface {
+
+    public static final String ARG_SHOW_NEW_FOR_USER = "ARG_SHOW_NEW_FOR_USER";
 
     private static final String TAG = "TrustedCredentialsSettings";
 
     private UserManager mUserManager;
     private KeyguardManager mKeyguardManager;
+    private int mTrustAllCaUserId;
+
 
     private static final String USER_ACTION = "com.android.settings.TRUSTED_CREDENTIALS_USER";
 
@@ -135,30 +134,6 @@
             }
             throw new AssertionError();
         }
-        private int getButtonLabel(CertHolder certHolder) {
-            switch (this) {
-                case SYSTEM:
-                    if (certHolder.mDeleted) {
-                        return R.string.trusted_credentials_enable_label;
-                    }
-                    return R.string.trusted_credentials_disable_label;
-                case USER:
-                    return R.string.trusted_credentials_remove_label;
-            }
-            throw new AssertionError();
-        }
-        private int getButtonConfirmation(CertHolder certHolder) {
-            switch (this) {
-                case SYSTEM:
-                    if (certHolder.mDeleted) {
-                        return R.string.trusted_credentials_enable_confirmation;
-                    }
-                    return R.string.trusted_credentials_disable_confirmation;
-                case USER:
-                    return R.string.trusted_credentials_remove_confirmation;
-            }
-            throw new AssertionError();
-        }
         private void postOperationUpdate(boolean ok, CertHolder certHolder) {
             if (ok) {
                 if (certHolder.mTab.mSwitch) {
@@ -213,6 +188,9 @@
         mUserManager = (UserManager) getActivity().getSystemService(Context.USER_SERVICE);
         mKeyguardManager = (KeyguardManager) getActivity()
                 .getSystemService(Context.KEYGUARD_SERVICE);
+        mTrustAllCaUserId = getActivity().getIntent().getIntExtra(ARG_SHOW_NEW_FOR_USER,
+                UserHandle.USER_NULL);
+
         IntentFilter filter = new IntentFilter();
         filter.addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE);
         filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
@@ -590,6 +568,37 @@
                 mList.setVisibility(View.VISIBLE);
                 mProgressBar.setProgress(0);
                 mAliasLoaders.remove(mTab);
+                showTrustAllCaDialogIfNeeded();
+            }
+
+            private boolean isUserTabAndTrustAllCertMode() {
+                return isTrustAllCaCertModeInProgress() && mTab == Tab.USER;
+            }
+
+            @UiThread
+            private void showTrustAllCaDialogIfNeeded() {
+                if (!isUserTabAndTrustAllCertMode()) {
+                    return;
+                }
+                List<CertHolder> certHolders = mCertHoldersByUserId.get(mTrustAllCaUserId);
+                if (certHolders == null) {
+                    return;
+                }
+
+                List<CertHolder> unapprovedUserCertHolders = new ArrayList<>();
+                final DevicePolicyManager dpm = mContext.getSystemService(
+                        DevicePolicyManager.class);
+                for (CertHolder cert : certHolders) {
+                    if (cert != null && !dpm.isCaCertApproved(cert.mAlias, mTrustAllCaUserId)) {
+                        unapprovedUserCertHolders.add(cert);
+                    }
+                }
+
+                if (unapprovedUserCertHolders.size() == 0) {
+                    Log.w(TAG, "no cert is pending approval for user " + mTrustAllCaUserId);
+                    return;
+                }
+                showTrustAllCaDialog(unapprovedUserCertHolders);
             }
         }
 
@@ -603,7 +612,7 @@
         }
     }
 
-    private static class CertHolder implements Comparable<CertHolder> {
+    /* package */ static class CertHolder implements Comparable<CertHolder> {
         public int mProfileId;
         private final IKeyChainService mService;
         private final TrustedCertificateAdapterCommons mAdapter;
@@ -679,6 +688,22 @@
         @Override public int hashCode() {
             return mAlias.hashCode();
         }
+
+        public int getUserId() {
+            return mProfileId;
+        }
+
+        public String getAlias() {
+            return mAlias;
+        }
+
+        public boolean isSystemCert() {
+            return mTab == Tab.SYSTEM;
+        }
+
+        public boolean isDeleted() {
+            return mDeleted;
+        }
     }
 
     private View getViewForCertificate(CertHolder certHolder, Tab mTab, View convertView,
@@ -716,91 +741,34 @@
         private Switch mSwitch;
     }
 
-    private void showCertDialog(final CertHolder certHolder) {
-        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
-        builder.setTitle(com.android.internal.R.string.ssl_certificate);
-
-        final DevicePolicyManager dpm = getActivity().getSystemService(DevicePolicyManager.class);
-        final ArrayList<View> views =  new ArrayList<View>();
-        final ArrayList<String> titles = new ArrayList<String>();
-        addCertChain(certHolder, views, titles);
-
-        ArrayAdapter<String> arrayAdapter = new ArrayAdapter<String>(getActivity(),
-                android.R.layout.simple_spinner_item,
-                titles);
-        arrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
-        Spinner spinner = new Spinner(getActivity());
-        spinner.setAdapter(arrayAdapter);
-        spinner.setOnItemSelectedListener(new OnItemSelectedListener() {
-            @Override
-            public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
-                for (int i = 0; i < views.size(); i++) {
-                    views.get(i).setVisibility(i == position ? View.VISIBLE : View.GONE);
-                }
-            }
-
-            @Override
-            public void onNothingSelected(AdapterView<?> parent) {
-            }
-        });
-
-        LinearLayout container = new LinearLayout(getActivity());
-        container.setOrientation(LinearLayout.VERTICAL);
-        container.addView(spinner);
-        for (int i = 0; i < views.size(); ++i) {
-            View certificateView = views.get(i);
-            if (i != 0) {
-                certificateView.setVisibility(View.GONE);
-            }
-            container.addView(certificateView);
-        }
-        builder.setView(container);
-
-        if (certHolder.mTab == Tab.USER &&
-                !dpm.isCaCertApproved(certHolder.mAlias, certHolder.mProfileId)) {
-            builder.setPositiveButton(R.string.trusted_credentials_trust_label,
-                    new DialogInterface.OnClickListener() {
-                        @Override
-                        public void onClick(DialogInterface dialog, int id) {
-                            dpm.approveCaCert(certHolder.mAlias, certHolder.mProfileId, true);
-                        }
-                    });
-        } else {
-            // The ok button is optional. Display it only when trust button is not displayed.
-            // User can still dismiss the dialog by other means.
-            builder.setPositiveButton(android.R.string.ok, null);
-        }
-
-        if (!mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_CREDENTIALS,
-                new UserHandle(certHolder.mProfileId))) {
-            builder.setNegativeButton(certHolder.mTab.getButtonLabel(certHolder),
-                    new DialogInterface.OnClickListener() {
-                        @Override
-                        public void onClick(final DialogInterface parentDialog, int i) {
-                            AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
-                            builder.setMessage(certHolder.mTab.getButtonConfirmation(certHolder));
-                            builder.setPositiveButton(android.R.string.yes,
-                                    new DialogInterface.OnClickListener() {
-                                        @Override
-                                        public void onClick(DialogInterface dialog, int id) {
-                                            new AliasOperation(certHolder).execute();
-                                            dialog.dismiss();
-                                            parentDialog.dismiss();
-                                        }
-                                    });
-                            builder.setNegativeButton(android.R.string.no, null);
-                            AlertDialog alert = builder.create();
-                            alert.show();
-                        }
-                    });
-        }
-
-        builder.show();
+    private boolean isTrustAllCaCertModeInProgress() {
+        return mTrustAllCaUserId != UserHandle.USER_NULL;
     }
 
-    private void addCertChain(final CertHolder certHolder,
-            final ArrayList<View> views, final ArrayList<String> titles) {
+    private void showTrustAllCaDialog(List<CertHolder> unapprovedCertHolders) {
+        final CertHolder[] arr = unapprovedCertHolders.toArray(
+                new CertHolder[unapprovedCertHolders.size()]);
+        new TrustedCredentialsDialogBuilder(getActivity(), this)
+                .setCertHolders(arr)
+                .setOnDismissListener(new DialogInterface.OnDismissListener() {
+                    @Override
+                    public void onDismiss(DialogInterface dialogInterface) {
+                        // Avoid starting dialog again after Activity restart.
+                        getActivity().getIntent().removeExtra(ARG_SHOW_NEW_FOR_USER);
+                        mTrustAllCaUserId = UserHandle.USER_NULL;
+                    }
+                })
+                .show();
+    }
 
+    private void showCertDialog(final CertHolder certHolder) {
+        new TrustedCredentialsDialogBuilder(getActivity(), this)
+                .setCertHolder(certHolder)
+                .show();
+    }
+
+    @Override
+    public List<X509Certificate> getX509CertsFromCertHolder(CertHolder certHolder) {
         List<X509Certificate> certificates = null;
         try {
             KeyChainConnection keyChainConnection = mKeyChainConnectionByProfileId.get(
@@ -817,18 +785,13 @@
         } catch (RemoteException ex) {
             Log.e(TAG, "RemoteException while retrieving certificate chain for root "
                     + certHolder.mAlias, ex);
-            return;
         }
-        for (X509Certificate certificate : certificates) {
-            addCertDetails(certificate, views, titles);
-        }
+        return certificates;
     }
 
-    private void addCertDetails(X509Certificate certificate, final ArrayList<View> views,
-            final ArrayList<String> titles) {
-        SslCertificate sslCert = new SslCertificate(certificate);
-        views.add(sslCert.inflateCertificateView(getActivity()));
-        titles.add(sslCert.getIssuedTo().getCName());
+    @Override
+    public void removeOrInstallCert(CertHolder certHolder) {
+        new AliasOperation(certHolder).execute();
     }
 
     private class AliasOperation extends AsyncTask<Void, Void, Boolean> {
@@ -854,8 +817,7 @@
                 }
             } catch (CertificateEncodingException | SecurityException | IllegalStateException
                     | RemoteException e) {
-                Log.w(TAG, "Error while toggling alias " + mCertHolder.mAlias,
-                        e);
+                Log.w(TAG, "Error while toggling alias " + mCertHolder.mAlias, e);
                 return false;
             }
         }
diff --git a/src/com/android/settings/Utils.java b/src/com/android/settings/Utils.java
index 527194f..4dd203c 100644
--- a/src/com/android/settings/Utils.java
+++ b/src/com/android/settings/Utils.java
@@ -87,6 +87,8 @@
 import android.view.animation.AnimationUtils;
 import android.widget.ListView;
 import android.widget.TabWidget;
+
+import com.android.internal.app.UnlaunchableAppActivity;
 import com.android.internal.util.UserIcons;
 
 import java.io.IOException;
@@ -1104,5 +1106,15 @@
         return Settings.Global.getInt(context.getContentResolver(),
                 Settings.Global.DEVICE_PROVISIONED, 0) != 0;
     }
+
+    public static boolean startQuiteModeDialogIfNecessary(Context context, UserManager um,
+            int userId) {
+        if (um.isQuietModeEnabled(UserHandle.of(userId))) {
+            final Intent intent = UnlaunchableAppActivity.createInQuietModeDialogIntent(userId);
+            context.startActivity(intent);
+            return true;
+        }
+        return false;
+    }
 }
 
diff --git a/src/com/android/settings/applications/InstalledAppDetails.java b/src/com/android/settings/applications/InstalledAppDetails.java
index f91f7bf..035b504 100755
--- a/src/com/android/settings/applications/InstalledAppDetails.java
+++ b/src/com/android/settings/applications/InstalledAppDetails.java
@@ -424,7 +424,7 @@
 
     private Intent resolveIntent(Intent i) {
         ResolveInfo result = getContext().getPackageManager().resolveActivity(i, 0);
-        return result != null ? new Intent(Intent.ACTION_APPLICATION_PREFERENCES)
+        return result != null ? new Intent(i.getAction())
                 .setClassName(result.activityInfo.packageName, result.activityInfo.name) : null;
     }
 
@@ -902,6 +902,26 @@
                 category.addPreference(pref);
             }
         }
+
+        final String installerPackageName =
+                getContext().getPackageManager().getInstallerPackageName(mPackageName);
+        if (installerPackageName != null) {
+            final Intent intent = new Intent(Intent.ACTION_SHOW_APP_INFO)
+                    .setPackage(installerPackageName);
+            final Intent result = resolveIntent(intent);
+            if (result != null) {
+                result.putExtra(Intent.EXTRA_PACKAGE_NAME, mPackageName);
+                PreferenceCategory category = new PreferenceCategory(getPrefContext());
+                category.setTitle(R.string.app_install_details_group_title);
+                screen.addPreference(category);
+                Preference pref = new Preference(getPrefContext());
+                pref.setTitle(R.string.app_install_details_title);
+                pref.setKey("app_info_store");
+                pref.setSummary(getString(R.string.app_install_details_summary, mAppEntry.label));
+                pref.setIntent(result);
+                category.addPreference(pref);
+            }
+        }
     }
 
     private boolean hasPermission(String permission) {
diff --git a/src/com/android/settings/dashboard/DashboardDecorator.java b/src/com/android/settings/dashboard/DashboardDecorator.java
index 2e7afaf..9bcf39d 100644
--- a/src/com/android/settings/dashboard/DashboardDecorator.java
+++ b/src/com/android/settings/dashboard/DashboardDecorator.java
@@ -21,7 +21,6 @@
 import android.support.v7.widget.RecyclerView;
 import android.support.v7.widget.RecyclerView.State;
 import android.support.v7.widget.RecyclerView.ViewHolder;
-import android.util.Log;
 import android.util.TypedValue;
 import android.view.View;
 import com.android.settings.R;
@@ -41,8 +40,6 @@
     @Override
     public void onDrawOver(Canvas c, RecyclerView parent, State state) {
         final int childCount = parent.getChildCount();
-        final int width = parent.getWidth();
-        final int bottom = parent.getBottom();
         for (int i = 1; i < childCount; i++) {
             final View child = parent.getChildAt(i);
             final ViewHolder holder = parent.getChildViewHolder(child);
@@ -56,7 +53,8 @@
             }
 
             int top = getChildTop(child);
-            mDivider.setBounds(0, top, width, top + mDivider.getIntrinsicHeight());
+            mDivider.setBounds(child.getLeft(), top, child.getRight(),
+                    top + mDivider.getIntrinsicHeight());
             mDivider.draw(c);
         }
     }
diff --git a/src/com/android/settings/datausage/AppDataUsage.java b/src/com/android/settings/datausage/AppDataUsage.java
index 11b100c..b3c8e03 100644
--- a/src/com/android/settings/datausage/AppDataUsage.java
+++ b/src/com/android/settings/datausage/AppDataUsage.java
@@ -20,6 +20,7 @@
 import android.content.Loader;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
+import android.content.pm.UserInfo;
 import android.graphics.drawable.Drawable;
 import android.net.INetworkStatsSession;
 import android.net.NetworkPolicy;
@@ -30,6 +31,7 @@
 import android.os.Bundle;
 import android.os.RemoteException;
 import android.os.UserHandle;
+import android.os.UserManager;
 import android.support.v14.preference.SwitchPreference;
 import android.support.v7.preference.Preference;
 import android.support.v7.preference.PreferenceCategory;
@@ -42,8 +44,10 @@
 import com.android.settings.R;
 import com.android.settings.applications.AppInfoBase;
 import com.android.settingslib.AppItem;
+import com.android.settingslib.Utils;
 import com.android.settingslib.net.ChartData;
 import com.android.settingslib.net.ChartDataLoader;
+import com.android.settingslib.net.UidDetailProvider;
 
 import static android.net.NetworkPolicyManager.POLICY_NONE;
 import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND;
@@ -123,15 +127,6 @@
                 addUid(mAppItem.uids.keyAt(i));
             }
         }
-        if (mPackages.size() != 0) {
-            PackageManager pm = getPackageManager();
-            try {
-                ApplicationInfo info = pm.getApplicationInfo(mPackages.valueAt(0), 0);
-                mIcon = info.loadIcon(pm);
-                mLabel = info.loadLabel(pm);
-            } catch (PackageManager.NameNotFoundException e) {
-            }
-        }
         addPreferencesFromResource(R.xml.app_data_usage);
 
         mTotalUsage = findPreference(KEY_TOTAL_USAGE);
@@ -142,6 +137,15 @@
         mCycleAdapter = new CycleAdapter(getContext(), mCycle, mCycleListener, false);
 
         if (UserHandle.isApp(mAppItem.key)) {
+            if (mPackages.size() != 0) {
+                PackageManager pm = getPackageManager();
+                try {
+                    ApplicationInfo info = pm.getApplicationInfo(mPackages.valueAt(0), 0);
+                    mIcon = info.loadIcon(pm);
+                    mLabel = info.loadLabel(pm);
+                } catch (PackageManager.NameNotFoundException e) {
+                }
+            }
             mRestrictBackground = (SwitchPreference) findPreference(KEY_RESTRICT_BACKGROUND);
             mRestrictBackground.setOnPreferenceChangeListener(this);
             mUnrestrictedData = (SwitchPreference) findPreference(KEY_UNRESTRICTED_DATA);
@@ -176,6 +180,12 @@
                 removePreference(KEY_APP_LIST);
             }
         } else {
+            final int userId = UidDetailProvider.getUserIdForKey(mAppItem.key);
+            final UserManager um = UserManager.get(getActivity());
+            final UserInfo info = um.getUserInfo(userId);
+            final PackageManager pm = getPackageManager();
+            mIcon = Utils.getUserIcon(getActivity(), um, info);
+            mLabel = Utils.getUserLabel(getActivity(), info);
             removePreference(KEY_UNRESTRICTED_DATA);
             removePreference(KEY_APP_SETTINGS);
             removePreference(KEY_RESTRICT_BACKGROUND);
diff --git a/src/com/android/settings/datausage/DataSaverSummary.java b/src/com/android/settings/datausage/DataSaverSummary.java
index e12afbf..e8c8cdd 100644
--- a/src/com/android/settings/datausage/DataSaverSummary.java
+++ b/src/com/android/settings/datausage/DataSaverSummary.java
@@ -100,6 +100,9 @@
 
     @Override
     public void onExtraInfoUpdated() {
+        if (!isAdded()) {
+            return;
+        }
         int count = 0;
         final ArrayList<AppEntry> allApps = mSession.getAllApps();
         final int N = allApps.size();
diff --git a/src/com/android/settings/deviceinfo/PrivateVolumeSettings.java b/src/com/android/settings/deviceinfo/PrivateVolumeSettings.java
index a19b5b8..5f5975d 100644
--- a/src/com/android/settings/deviceinfo/PrivateVolumeSettings.java
+++ b/src/com/android/settings/deviceinfo/PrivateVolumeSettings.java
@@ -725,11 +725,16 @@
                 public void onClick(DialogInterface dialog, int which) {
                     final PrivateVolumeSettings target = (PrivateVolumeSettings) getTargetFragment();
                     final PackageManager pm = context.getPackageManager();
-                    final List<PackageInfo> infos = pm.getInstalledPackages(0);
-                    final ClearCacheObserver observer = new ClearCacheObserver(
-                            target, infos.size());
-                    for (PackageInfo info : infos) {
-                        pm.deleteApplicationCacheFiles(info.packageName, observer);
+                    final UserManager um = context.getSystemService(UserManager.class);
+
+                    for (int userId : um.getProfileIdsWithDisabled(context.getUserId())) {
+                        final List<PackageInfo> infos = pm.getInstalledPackagesAsUser(0, userId);
+                        final ClearCacheObserver observer = new ClearCacheObserver(
+                                target, infos.size());
+                        for (PackageInfo info : infos) {
+                            pm.deleteApplicationCacheFilesAsUser(info.packageName, userId,
+                                    observer);
+                        }
                     }
                 }
             });
diff --git a/src/com/android/settings/fingerprint/FingerprintSettings.java b/src/com/android/settings/fingerprint/FingerprintSettings.java
index 9e2c5ff..3b83e48 100644
--- a/src/com/android/settings/fingerprint/FingerprintSettings.java
+++ b/src/com/android/settings/fingerprint/FingerprintSettings.java
@@ -40,6 +40,7 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.support.v7.preference.Preference;
+import android.support.v7.preference.Preference.OnPreferenceClickListener;
 import android.support.v7.preference.Preference.OnPreferenceChangeListener;
 import android.support.v7.preference.PreferenceGroup;
 import android.support.v7.preference.PreferenceScreen;
@@ -808,7 +809,7 @@
         }
     }
 
-    public static Preference getFingerprintPreferenceForUser(Context context, int userId) {
+    public static Preference getFingerprintPreferenceForUser(Context context, final int userId) {
         FingerprintManager fpm = (FingerprintManager) context.getSystemService(
                 Context.FINGERPRINT_SERVICE);
         if (fpm == null || !fpm.isHardwareDetected()) {
@@ -818,7 +819,6 @@
         Preference fingerprintPreference = new Preference(context);
         fingerprintPreference.setKey(KEY_FINGERPRINT_SETTINGS);
         fingerprintPreference.setTitle(R.string.security_settings_fingerprint_preference_title);
-        Intent intent = new Intent();
         final List<Fingerprint> items = fpm.getEnrolledFingerprints(userId);
         final int fingerprintCount = items != null ? items.size() : 0;
         final String clazz;
@@ -832,9 +832,22 @@
                     R.string.security_settings_fingerprint_preference_summary_none);
             clazz = FingerprintEnrollIntroduction.class.getName();
         }
-        intent.setClassName("com.android.settings", clazz);
-        intent.putExtra(Intent.EXTRA_USER_ID, userId);
-        fingerprintPreference.setIntent(intent);
+        fingerprintPreference.setOnPreferenceClickListener(new OnPreferenceClickListener() {
+            @Override
+            public boolean onPreferenceClick(Preference preference) {
+                final Context context = preference.getContext();
+                final UserManager userManager = UserManager.get(context);
+                if (Utils.startQuiteModeDialogIfNecessary(context, userManager,
+                        userId)) {
+                    return false;
+                }
+                Intent intent = new Intent();
+                intent.setClassName("com.android.settings", clazz);
+                intent.putExtra(Intent.EXTRA_USER_ID, userId);
+                context.startActivity(intent);
+                return true;
+            }
+        });
         return fingerprintPreference;
     }
 }
diff --git a/src/com/android/settings/tts/TextToSpeechSettings.java b/src/com/android/settings/tts/TextToSpeechSettings.java
index c8f7b88..0a48874 100644
--- a/src/com/android/settings/tts/TextToSpeechSettings.java
+++ b/src/com/android/settings/tts/TextToSpeechSettings.java
@@ -93,14 +93,15 @@
     private static final int MAX_SPEECH_RATE = 600;
 
     /**
-     * Maximum speech pitch value. Pitch value varies from 50 to 500, where 100
-     * is the value for normal pitch. The max pitch value is set to 500, based on
-     * feedback from a few accessibility users. The range for pitch is not set in stone,
+     * Speech pitch value.
+     * TTS pitch value varies from 25 to 400, where 100 is the value
+     * for normal pitch. The max pitch value is set to 400, based on feedback from users
+     * and the GoogleTTS pitch variation range. The range for pitch is not set in stone
      * and should be readjusted based on user need.
-     *
      * This value should be kept in sync with the max value set in tts_settings xml.
      */
-    private static final int MAX_SPEECH_PITCH = 500;
+    private static final int MAX_SPEECH_PITCH = 400;
+    private static final int MIN_SPEECH_PITCH = 25;
 
     private PreferenceCategory mEnginePreferenceCategory;
     private SeekBarPreference mDefaultPitchPref;
@@ -264,9 +265,9 @@
         mDefaultRatePref.setOnPreferenceChangeListener(this);
         mDefaultRatePref.setMax(MAX_SPEECH_RATE);
 
-        mDefaultPitchPref.setProgress(mDefaultPitch);
+        mDefaultPitchPref.setProgress(getPitchSeekBarProgressFromSpeechPitchValue(mDefaultPitch));
         mDefaultPitchPref.setOnPreferenceChangeListener(this);
-        mDefaultPitchPref.setMax(MAX_SPEECH_PITCH);
+        mDefaultPitchPref.setMax(getPitchSeekBarProgressFromSpeechPitchValue(MAX_SPEECH_PITCH));
 
         mCurrentEngine = mTts.getCurrentEngine();
 
@@ -291,6 +292,24 @@
     }
 
     /**
+     * The minimum pitch value should be > 0 but the minimum value of a seekbar in android
+     * is fixed at 0. Therefore, we increment the seekbar progress with MIN_SPEECH_PITCH value
+     * so that the minimum seekbar progress value is MIN_SPEECH_PITCH.
+     *     PITCH_VALUE = MIN_SPEECH_PITCH + PITCH_SEEKBAR_PROGRESS
+     */
+    private int getSpeechPitchValueFromSeekBarProgress(int progress) {
+        return MIN_SPEECH_PITCH + progress;
+    }
+
+    /**
+     * Since we are appending the MIN_SPEECH_PITCH to the pitch seekbar progress, the pitch
+     * seekbar progress should be set to (pitchValue - MIN_SPEECH_PITCH).
+     */
+    private int getPitchSeekBarProgressFromSpeechPitchValue(int pitchValue) {
+        return pitchValue - MIN_SPEECH_PITCH;
+    }
+
+    /**
      * Called when the TTS engine is initialized.
      */
     public void onInitEngine(int status) {
@@ -484,9 +503,10 @@
     @Override
     public boolean onPreferenceChange(Preference preference, Object objValue) {
         if (KEY_DEFAULT_RATE.equals(preference.getKey())) {
-            updateSpeechRate(((Integer) objValue).intValue());
+            updateSpeechRate((Integer) objValue);
         } else if (KEY_DEFAULT_PITCH.equals(preference.getKey())) {
-            mDefaultPitch = ((Integer) objValue).intValue();
+            int progress = (Integer) objValue;
+            mDefaultPitch = getSpeechPitchValueFromSeekBarProgress(progress);
             try {
                 android.provider.Settings.Secure.putInt(getContentResolver(),
                         TTS_DEFAULT_PITCH, mDefaultPitch);
diff --git a/src/com/android/settings/vpn2/ConfigDialog.java b/src/com/android/settings/vpn2/ConfigDialog.java
index a13e29d..92050e9 100644
--- a/src/com/android/settings/vpn2/ConfigDialog.java
+++ b/src/com/android/settings/vpn2/ConfigDialog.java
@@ -170,6 +170,9 @@
             // Show type-specific fields.
             changeType(mProfile.type);
 
+            // Hide 'save login' when we are editing.
+            mSaveLogin.setVisibility(View.GONE);
+
             // Switch to advanced view immediately if any advanced options are on
             if (!mProfile.searchDomains.isEmpty() || !mProfile.dnsServers.isEmpty() ||
                     !mProfile.routes.isEmpty()) {
@@ -188,9 +191,6 @@
         } else {
             setTitle(context.getString(R.string.vpn_connect_to, mProfile.name));
 
-            // Not editing, just show username and password.
-            mView.findViewById(R.id.login).setVisibility(View.VISIBLE);
-
             // Create a button to connect the network.
             setButton(DialogInterface.BUTTON_POSITIVE,
                     context.getString(R.string.vpn_connect), mListener);
@@ -259,6 +259,7 @@
     public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
         if (compoundButton == mAlwaysOnVpn) {
             updateSaveLoginStatus();
+            getButton(DialogInterface.BUTTON_POSITIVE).setEnabled(validate(mEditing));
         }
     }
 
@@ -318,6 +319,9 @@
         if (!editing) {
             return mUsername.getText().length() != 0 && mPassword.getText().length() != 0;
         }
+        if (mAlwaysOnVpn.isChecked() && !getProfile().isValidLockdownProfile()) {
+            return false;
+        }
         if (mName.getText().length() == 0 || mServer.getText().length() == 0 ||
                 !validateAddresses(mDnsServers.getText().toString(), false) ||
                 !validateAddresses(mRoutes.getText().toString(), true)) {
@@ -441,7 +445,8 @@
                 break;
         }
 
-        profile.saveLogin = mSaveLogin.isChecked();
+        final boolean hasLogin = !profile.username.isEmpty() || !profile.password.isEmpty();
+        profile.saveLogin = mSaveLogin.isChecked() || (mEditing && hasLogin);
         return profile;
     }
 }
diff --git a/src/com/android/settings/vpn2/ConfigDialogFragment.java b/src/com/android/settings/vpn2/ConfigDialogFragment.java
index fc49fd8..5e4a7d9 100644
--- a/src/com/android/settings/vpn2/ConfigDialogFragment.java
+++ b/src/com/android/settings/vpn2/ConfigDialogFragment.java
@@ -152,12 +152,9 @@
                 return;
             }
 
-            // Update only if lockdown vpn has been changed
-            if (!VpnUtils.isVpnLockdown(profile.key)) {
-                final ConnectivityManager conn = ConnectivityManager.from(getActivity());
-                conn.setAlwaysOnVpnPackageForUser(UserHandle.myUserId(), null);
-                VpnUtils.setLockdownVpn(getContext(), profile.key);
-            }
+            final ConnectivityManager conn = ConnectivityManager.from(getActivity());
+            conn.setAlwaysOnVpnPackageForUser(UserHandle.myUserId(), null);
+            VpnUtils.setLockdownVpn(getContext(), profile.key);
         } else {
             // update only if lockdown vpn has been changed
             if (VpnUtils.isVpnLockdown(profile.key)) {