Merge "Fix problem with message indent. b/25054130" into nyc-dev
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 95a7749..c726d0e 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -5229,6 +5229,8 @@
     <string name="trusted_credentials_enable_label">Enable</string>
     <!-- Button label for removing a user CA certificate. -->
     <string name="trusted_credentials_remove_label">Remove</string>
+    <!-- Button label for trusting a user CA certificate. -->
+    <string name="trusted_credentials_trust_label">Trust</string>
     <!-- Alert dialog confirmation when enabling a system CA certificate. -->
     <string name="trusted_credentials_enable_confirmation">Enable the system CA certificate?</string>
     <!-- Alert dialog confirmation when disabling a system CA certificate. -->
@@ -7364,4 +7366,10 @@
     <!-- Summary of notification suggestion during optional steps of setup. [CHAR_LIMIT=80] -->
     <string name="notification_suggestion_summary">Show or hide notification content</string>
 
+    <!-- Summary of developer options to set the smallest width of the screen [CHAR LIMIT=60]-->
+    <string name="developer_density_summary"><xliff:g name="count" example="320">%d</xliff:g> dp</string>
+
+    <!-- Title of developer options to set the smallest width of the screen [CHAR LIMIT=60]-->
+    <string name="developer_smallest_width">Smallest width</string>
+
 </resources>
diff --git a/res/xml/development_prefs.xml b/res/xml/development_prefs.xml
index e58ff95..7e8d2be 100644
--- a/res/xml/development_prefs.xml
+++ b/res/xml/development_prefs.xml
@@ -239,6 +239,10 @@
             android:entries="@array/overlay_display_devices_entries"
             android:entryValues="@array/overlay_display_devices_values" />
 
+        <com.android.settings.display.DensityPreference
+            android:key="density"
+            android:title="@string/developer_smallest_width" />
+
     </PreferenceCategory>
 
     <PreferenceCategory android:key="debug_hw_drawing_category"
diff --git a/res/xml/security_settings_lockscreen.xml b/res/xml/security_settings_lockscreen.xml
index a5aa767..c141fb7 100644
--- a/res/xml/security_settings_lockscreen.xml
+++ b/res/xml/security_settings_lockscreen.xml
@@ -22,7 +22,7 @@
         android:key="security_category"
         android:title="@string/lock_settings_title">
 
-        <PreferenceScreen
+        <com.android.settingslib.RestrictedPreference
             android:key="unlock_set_or_change"
             android:title="@string/unlock_set_unlock_launch_picker_title"
             android:summary="@string/unlock_set_unlock_mode_off"
diff --git a/res/xml/security_settings_lockscreen_profile.xml b/res/xml/security_settings_lockscreen_profile.xml
index 8f99c62..e027c6b 100644
--- a/res/xml/security_settings_lockscreen_profile.xml
+++ b/res/xml/security_settings_lockscreen_profile.xml
@@ -18,7 +18,7 @@
                   xmlns:settings="http://schemas.android.com/apk/res/com.android.settings"
                   android:title="@string/security_settings_title">
 
-    <PreferenceScreen
+    <com.android.settingslib.RestrictedPreference
         android:key="unlock_set_or_change_profile"
         android:title="@string/unlock_set_unlock_launch_picker_title_profile"
         android:summary="@string/unlock_set_unlock_mode_off"
diff --git a/res/xml/security_settings_password_profile.xml b/res/xml/security_settings_password_profile.xml
index 7aff0fd..84e1678 100644
--- a/res/xml/security_settings_password_profile.xml
+++ b/res/xml/security_settings_password_profile.xml
@@ -18,7 +18,7 @@
                   xmlns:settings="http://schemas.android.com/apk/res/com.android.settings"
                   android:title="@string/security_settings_title">
 
-    <PreferenceScreen
+    <com.android.settingslib.RestrictedPreference
         android:key="unlock_set_or_change_profile"
         android:title="@string/unlock_set_unlock_launch_picker_title_profile"
         android:summary="@string/unlock_set_unlock_mode_password"
diff --git a/res/xml/security_settings_pattern_profile.xml b/res/xml/security_settings_pattern_profile.xml
index 2010e0d..b660e4a 100644
--- a/res/xml/security_settings_pattern_profile.xml
+++ b/res/xml/security_settings_pattern_profile.xml
@@ -18,7 +18,7 @@
                   xmlns:settings="http://schemas.android.com/apk/res/com.android.settings"
                   android:title="@string/security_settings_title">
 
-    <PreferenceScreen
+    <com.android.settingslib.RestrictedPreference
         android:key="unlock_set_or_change_profile"
         android:title="@string/unlock_set_unlock_launch_picker_title_profile"
         android:summary="@string/unlock_set_unlock_mode_pattern"
diff --git a/res/xml/security_settings_pin_profile.xml b/res/xml/security_settings_pin_profile.xml
index 5c83072..481a087 100644
--- a/res/xml/security_settings_pin_profile.xml
+++ b/res/xml/security_settings_pin_profile.xml
@@ -18,7 +18,7 @@
                   xmlns:settings="http://schemas.android.com/apk/res/com.android.settings"
                   android:title="@string/security_settings_title">
 
-    <PreferenceScreen
+    <com.android.settingslib.RestrictedPreference
         android:key="unlock_set_or_change_profile"
         android:title="@string/unlock_set_unlock_launch_picker_title_profile"
         android:summary="@string/unlock_set_unlock_mode_pin"
diff --git a/src/com/android/settings/CustomEditTextPreference.java b/src/com/android/settings/CustomEditTextPreference.java
index 7bb1d86..66c6932 100644
--- a/src/com/android/settings/CustomEditTextPreference.java
+++ b/src/com/android/settings/CustomEditTextPreference.java
@@ -105,6 +105,7 @@
 
         @Override
         public void onDialogClosed(boolean positiveResult) {
+            super.onDialogClosed(positiveResult);
             getCustomizablePreference().onDialogClosed(positiveResult);
         }
 
diff --git a/src/com/android/settings/SecuritySettings.java b/src/com/android/settings/SecuritySettings.java
index e046175..32cd348 100644
--- a/src/com/android/settings/SecuritySettings.java
+++ b/src/com/android/settings/SecuritySettings.java
@@ -228,14 +228,8 @@
         final int resid = getResIdForLockUnlockScreen(getActivity(), mLockPatternUtils, MY_USER_ID);
         addPreferencesFromResource(resid);
 
-        final EnforcedAdmin admin = RestrictedLockUtils.checkIfPasswordQualityIsSet(
-                getActivity(), MY_USER_ID);
-        if (admin != null && mDPM.getPasswordQuality(admin.component) ==
-                DevicePolicyManager.PASSWORD_QUALITY_MANAGED) {
-            final GearPreference unlockSetOrChangePref =
-                    (GearPreference) getPreferenceScreen().findPreference(KEY_UNLOCK_SET_OR_CHANGE);
-            unlockSetOrChangePref.setDisabledByAdmin(admin);
-        }
+        // DO or PO installed in the user may disallow to change password.
+        disableIfPasswordQualityManaged(KEY_UNLOCK_SET_OR_CHANGE, MY_USER_ID);
 
         mProfileChallengeUserId = Utils.getManagedProfileId(mUm, MY_USER_ID);
         if (mProfileChallengeUserId != UserHandle.USER_NULL
@@ -247,11 +241,20 @@
             addPreferencesFromResource(profileResid);
             maybeAddFingerprintPreference(root, mProfileChallengeUserId);
             if (!mLockPatternUtils.isSeparateProfileChallengeEnabled(mProfileChallengeUserId)) {
-                Preference lockPreference = root.findPreference(KEY_UNLOCK_SET_OR_CHANGE_PROFILE);
-                String summary = getContext().getString(
+                final Preference lockPreference =
+                        root.findPreference(KEY_UNLOCK_SET_OR_CHANGE_PROFILE);
+                final String summary = getContext().getString(
                         R.string.lock_settings_profile_unified_summary);
                 lockPreference.setSummary(summary);
                 lockPreference.setEnabled(false);
+                // PO may disallow to change password for the profile, but screen lock and managed
+                // profile's lock is the same. Disable main "Screen lock" menu.
+                disableIfPasswordQualityManaged(KEY_UNLOCK_SET_OR_CHANGE, mProfileChallengeUserId);
+            } else {
+                // PO may disallow to change profile password, and the profile's password is
+                // separated from screen lock password. Disable profile specific "Screen lock" menu.
+                disableIfPasswordQualityManaged(KEY_UNLOCK_SET_OR_CHANGE_PROFILE,
+                        mProfileChallengeUserId);
             }
         }
 
@@ -393,6 +396,21 @@
         return root;
     }
 
+    /*
+     * Sets the preference as disabled by admin if PASSWORD_QUALITY_MANAGED is set.
+     * The preference must be a RestrictedPreference.
+     */
+    private void disableIfPasswordQualityManaged(String preferenceKey, int userId) {
+        final EnforcedAdmin admin = RestrictedLockUtils.checkIfPasswordQualityIsSet(
+                getActivity(), userId);
+        if (admin != null && mDPM.getPasswordQuality(admin.component, userId) ==
+                DevicePolicyManager.PASSWORD_QUALITY_MANAGED) {
+            final RestrictedPreference pref =
+                    (RestrictedPreference) getPreferenceScreen().findPreference(preferenceKey);
+            pref.setDisabledByAdmin(admin);
+        }
+    }
+
     private void maybeAddFingerprintPreference(PreferenceGroup securityCategory, int userId) {
         Preference fingerprintPreference =
                 FingerprintSettings.getFingerprintPreferenceForUser(
@@ -777,23 +795,26 @@
             final List<SearchIndexableResource> index = new ArrayList<SearchIndexableResource>();
 
             final LockPatternUtils lockPatternUtils = new LockPatternUtils(context);
-            final EnforcedAdmin admin = RestrictedLockUtils.checkIfPasswordQualityIsSet(
-                    context, MY_USER_ID);
             final DevicePolicyManager dpm = (DevicePolicyManager)
                     context.getSystemService(Context.DEVICE_POLICY_SERVICE);
             final UserManager um = UserManager.get(context);
+            final int profileUserId = Utils.getManagedProfileId(um, MY_USER_ID);
 
-            if (admin == null || dpm.getPasswordQuality(admin.component) !=
-                    DevicePolicyManager.PASSWORD_QUALITY_MANAGED) {
+            // To add option for unlock screen, user's password must not be managed and
+            // must not be unified with managed profile, whose password is managed.
+            if (!isPasswordManaged(MY_USER_ID, context, dpm)
+                    && (profileUserId == UserHandle.USER_NULL
+                            || lockPatternUtils.isSeparateProfileChallengeAllowed(profileUserId)
+                            || !isPasswordManaged(profileUserId, context, dpm))) {
                 // Add options for lock/unlock screen
                 final int resId = getResIdForLockUnlockScreen(context, lockPatternUtils,
                         MY_USER_ID);
                 index.add(getSearchResource(context, resId));
             }
 
-            final int profileUserId = Utils.getManagedProfileId(um, MY_USER_ID);
             if (profileUserId != UserHandle.USER_NULL
-                    && lockPatternUtils.isSeparateProfileChallengeAllowed(profileUserId)) {
+                    && lockPatternUtils.isSeparateProfileChallengeAllowed(profileUserId)
+                    && !isPasswordManaged(profileUserId, context, dpm)) {
                 index.add(getSearchResource(context, getResIdForLockUnlockScreen(context,
                         lockPatternUtils, profileUserId)));
             }
@@ -828,6 +849,13 @@
             return sir;
         }
 
+        private boolean isPasswordManaged(int userId, Context context, DevicePolicyManager dpm) {
+            final EnforcedAdmin admin = RestrictedLockUtils.checkIfPasswordQualityIsSet(
+                    context, userId);
+            return admin != null && dpm.getPasswordQuality(admin.component, userId) ==
+                    DevicePolicyManager.PASSWORD_QUALITY_MANAGED;
+        }
+
         @Override
         public List<SearchIndexableRaw> getRawDataToIndex(Context context, boolean enabled) {
             final List<SearchIndexableRaw> result = new ArrayList<SearchIndexableRaw>();
diff --git a/src/com/android/settings/TrustedCredentialsSettings.java b/src/com/android/settings/TrustedCredentialsSettings.java
index 2b73c3e..5e0aea7 100644
--- a/src/com/android/settings/TrustedCredentialsSettings.java
+++ b/src/com/android/settings/TrustedCredentialsSettings.java
@@ -19,6 +19,7 @@
 import android.app.AlertDialog;
 import android.app.Dialog;
 import android.app.KeyguardManager;
+import android.app.admin.DevicePolicyManager;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.DialogInterface;
@@ -719,6 +720,7 @@
         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);
@@ -730,16 +732,17 @@
         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 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) { }
-            });
+            }
+
+            @Override
+            public void onNothingSelected(AdapterView<?> parent) {
+            }
+        });
 
         LinearLayout container = new LinearLayout(getActivity());
         container.setOrientation(LinearLayout.VERTICAL);
@@ -752,47 +755,47 @@
             container.addView(certificateView);
         }
         builder.setView(container);
-        builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
-            @Override public void onClick(DialogInterface dialog, int id) {
-                dialog.dismiss();
-            }
-        });
-        final Dialog certDialog = builder.create();
 
-        ViewGroup body = (ViewGroup) container.findViewById(com.android.internal.R.id.body);
-        LayoutInflater inflater = LayoutInflater.from(getActivity());
-        Button removeButton = (Button) inflater.inflate(R.layout.trusted_credential_details,
-                                                        body,
-                                                        false);
+        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))) {
-            body.addView(removeButton);
+            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();
+                        }
+                    });
         }
-        removeButton.setText(certHolder.mTab.getButtonLabel(certHolder));
-        removeButton.setOnClickListener(new View.OnClickListener() {
-            @Override public void onClick(View v) {
-                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();
-                        certDialog.dismiss();
-                    }
-                });
-                builder.setNegativeButton(
-                        android.R.string.no, new DialogInterface.OnClickListener() {
-                    @Override public void onClick(DialogInterface dialog, int id) {
-                        dialog.cancel();
-                    }
-                });
-                AlertDialog alert = builder.create();
-                alert.show();
-            }
-        });
 
-        certDialog.show();
+        builder.show();
     }
 
     private void addCertChain(final CertHolder certHolder,
diff --git a/src/com/android/settings/bluetooth/BluetoothPairingDialog.java b/src/com/android/settings/bluetooth/BluetoothPairingDialog.java
index 182344c..48ca5a9 100755
--- a/src/com/android/settings/bluetooth/BluetoothPairingDialog.java
+++ b/src/com/android/settings/bluetooth/BluetoothPairingDialog.java
@@ -18,6 +18,7 @@
 
 import android.bluetooth.BluetoothClass;
 import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothUuid;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.DialogInterface;
@@ -43,6 +44,7 @@
 import com.android.settings.R;
 import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
 import com.android.settingslib.bluetooth.LocalBluetoothManager;
+import com.android.settingslib.bluetooth.LocalBluetoothProfile;
 
 import java.util.Locale;
 
@@ -64,6 +66,8 @@
     private String mPairingKey;
     private EditText mPairingView;
     private Button mOkButton;
+    private LocalBluetoothProfile mPbapClientProfile;
+
 
     /**
      * Dismiss the dialog if the bond state changes to bonded or none,
@@ -109,6 +113,7 @@
             return;
         }
         mCachedDeviceManager = mBluetoothManager.getCachedDeviceManager();
+        mPbapClientProfile = mBluetoothManager.getProfileManager().getPbapClientProfile();
 
         mDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
         mType = intent.getIntExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT, BluetoothDevice.ERROR);
@@ -188,6 +193,9 @@
                 R.id.phonebook_sharing_message_entry_pin);
         contactSharing.setText(getString(R.string.bluetooth_pairing_shares_phonebook,
                 mCachedDeviceManager.getName(mDevice)));
+        if (mPbapClientProfile != null && mPbapClientProfile.isProfileReady()) {
+            contactSharing.setVisibility(View.GONE);
+        }
         if (mDevice.getPhonebookAccessPermission() == BluetoothDevice.ACCESS_ALLOWED) {
             contactSharing.setChecked(true);
         } else if (mDevice.getPhonebookAccessPermission() == BluetoothDevice.ACCESS_REJECTED){
@@ -261,6 +269,9 @@
                 R.id.phonebook_sharing_message_confirm_pin);
         contactSharing.setText(getString(R.string.bluetooth_pairing_shares_phonebook,
                 mCachedDeviceManager.getName(mDevice)));
+        if (mPbapClientProfile != null && mPbapClientProfile.isProfileReady()) {
+            contactSharing.setVisibility(View.GONE);
+        }
         if (mDevice.getPhonebookAccessPermission() == BluetoothDevice.ACCESS_ALLOWED) {
             contactSharing.setChecked(true);
         } else if (mDevice.getPhonebookAccessPermission() == BluetoothDevice.ACCESS_REJECTED){
diff --git a/src/com/android/settings/display/DensityPreference.java b/src/com/android/settings/display/DensityPreference.java
new file mode 100644
index 0000000..44013e3
--- /dev/null
+++ b/src/com/android/settings/display/DensityPreference.java
@@ -0,0 +1,74 @@
+/*
+ * 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.display;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.text.InputType;
+import android.util.AttributeSet;
+import android.util.DisplayMetrics;
+import android.view.Display;
+import android.view.View;
+import android.widget.EditText;
+import com.android.settings.CustomEditTextPreference;
+import com.android.settings.R;
+import com.android.settingslib.display.DisplayDensityUtils;
+
+public class DensityPreference extends CustomEditTextPreference {
+
+    public DensityPreference(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    @Override
+    public void onAttached() {
+        super.onAttached();
+
+        setSummary(getContext().getString(R.string.developer_density_summary, getCurrentSwDp()));
+    }
+
+    private int getCurrentSwDp() {
+        final Resources res = getContext().getResources();
+        final DisplayMetrics metrics = res.getDisplayMetrics();
+        final float density = metrics.density;
+        final int minDimensionPx = Math.min(metrics.widthPixels, metrics.heightPixels);
+        return (int) (minDimensionPx / density);
+    }
+
+    @Override
+    protected void onBindDialogView(View view) {
+        super.onBindDialogView(view);
+
+        final EditText editText = (EditText) view.findViewById(android.R.id.edit);
+
+        if (editText != null) {
+            editText.setInputType(InputType.TYPE_CLASS_NUMBER);
+            editText.setText(getCurrentSwDp() + "");
+        }
+    }
+
+    @Override
+    protected void onDialogClosed(boolean positiveResult) {
+        if (positiveResult) {
+            final Resources res = getContext().getResources();
+            final DisplayMetrics metrics = res.getDisplayMetrics();
+            final int newSwDp = Math.max(Integer.parseInt(getText()), 320);
+            final int minDimensionPx = Math.min(metrics.widthPixels, metrics.heightPixels);
+            final int newDensity = DisplayMetrics.DENSITY_MEDIUM * minDimensionPx / newSwDp;
+            final int densityDpi = Math.max(newDensity, 120);
+            DisplayDensityUtils.setForcedDisplayDensity(Display.DEFAULT_DISPLAY, densityDpi);
+        }
+    }
+}
diff --git a/src/com/android/settings/users/EditUserInfoController.java b/src/com/android/settings/users/EditUserInfoController.java
index a4c07bd..315ebcb 100644
--- a/src/com/android/settings/users/EditUserInfoController.java
+++ b/src/com/android/settings/users/EditUserInfoController.java
@@ -40,6 +40,8 @@
 import com.android.settingslib.Utils;
 import com.android.settingslib.drawable.CircleFramedDrawable;
 
+import java.io.File;
+
 /**
  * This class encapsulates a Dialog for editing the user nickname and photo.
  */
@@ -61,6 +63,7 @@
     }
 
     public void clear() {
+        mEditUserPhotoController.removeNewUserPhotoBitmapFile();
         mEditUserInfoDialog = null;
         mSavedPhoto = null;
     }
@@ -70,19 +73,25 @@
     }
 
     public void onRestoreInstanceState(Bundle icicle) {
-        mSavedPhoto = (Bitmap) icicle.getParcelable(KEY_SAVED_PHOTO);
+        String pendingPhoto = icicle.getString(KEY_SAVED_PHOTO);
+        if (pendingPhoto != null) {
+            mSavedPhoto = EditUserPhotoController.loadNewUserPhotoBitmap(new File(pendingPhoto));
+        }
         mWaitingForActivityResult = icicle.getBoolean(KEY_AWAITING_RESULT, false);
     }
 
     public void onSaveInstanceState(Bundle outState) {
         if (mEditUserInfoDialog != null && mEditUserInfoDialog.isShowing()
                 && mEditUserPhotoController != null) {
-            outState.putParcelable(KEY_SAVED_PHOTO,
-                    mEditUserPhotoController.getNewUserPhotoBitmap());
+            // Bitmap cannot be stored into bundle because it may exceed parcel limit
+            // Store it in a temporary file instead
+            File file = mEditUserPhotoController.saveNewUserPhotoBitmap();
+            if (file != null) {
+                outState.putString(KEY_SAVED_PHOTO, file.getPath());
+            }
         }
         if (mWaitingForActivityResult) {
-            outState.putBoolean(KEY_AWAITING_RESULT,
-                    mWaitingForActivityResult);
+            outState.putBoolean(KEY_AWAITING_RESULT, mWaitingForActivityResult);
         }
     }
 
diff --git a/src/com/android/settings/users/EditUserPhotoController.java b/src/com/android/settings/users/EditUserPhotoController.java
index 0d327a0..01b553c 100644
--- a/src/com/android/settings/users/EditUserPhotoController.java
+++ b/src/com/android/settings/users/EditUserPhotoController.java
@@ -50,8 +50,10 @@
 
 import java.io.File;
 import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.io.OutputStream;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -69,6 +71,7 @@
 
     private static final String CROP_PICTURE_FILE_NAME = "CropEditUserPhoto.jpg";
     private static final String TAKE_PICTURE_FILE_NAME = "TakeEditUserPhoto2.jpg";
+    private static final String NEW_USER_PHOTO_FILE_NAME = "NewUserPhoto.png";
 
     private final int mPhotoSize;
 
@@ -329,9 +332,33 @@
         if (purge) {
             fullPath.delete();
         }
-        final Uri fileUri =
-                FileProvider.getUriForFile(context, RestrictedProfileSettings.FILE_PROVIDER_AUTHORITY, fullPath);
-        return fileUri;
+        return FileProvider.getUriForFile(context,
+                RestrictedProfileSettings.FILE_PROVIDER_AUTHORITY, fullPath);
+    }
+
+    File saveNewUserPhotoBitmap() {
+        if (mNewUserPhotoBitmap == null) {
+            return null;
+        }
+        try {
+            File file = new File(mContext.getCacheDir(), NEW_USER_PHOTO_FILE_NAME);
+            OutputStream os = new FileOutputStream(file);
+            mNewUserPhotoBitmap.compress(Bitmap.CompressFormat.PNG, 100, os);
+            os.flush();
+            os.close();
+            return file;
+        } catch (IOException e) {
+            Log.e(TAG, "Cannot create temp file", e);
+        }
+        return null;
+    }
+
+    static Bitmap loadNewUserPhotoBitmap(File file) {
+        return BitmapFactory.decodeFile(file.getAbsolutePath());
+    }
+
+    void removeNewUserPhotoBitmapFile() {
+        new File(mContext.getCacheDir(), NEW_USER_PHOTO_FILE_NAME).delete();
     }
 
     private static final class AdapterItem {