1 /* 2 * Copyright (C) 2013 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.settings.users; 18 19 import android.app.Activity; 20 import android.app.Dialog; 21 import android.content.DialogInterface; 22 import android.content.Intent; 23 import android.content.pm.UserInfo; 24 import android.graphics.Bitmap; 25 import android.graphics.drawable.Drawable; 26 import android.os.AsyncTask; 27 import android.os.Bundle; 28 import android.os.UserHandle; 29 import android.os.UserManager; 30 import android.text.TextUtils; 31 import android.view.LayoutInflater; 32 import android.view.View; 33 import android.view.WindowManager; 34 import android.widget.EditText; 35 import android.widget.ImageView; 36 37 import androidx.annotation.VisibleForTesting; 38 import androidx.appcompat.app.AlertDialog; 39 import androidx.fragment.app.Fragment; 40 41 import com.android.settings.R; 42 import com.android.settingslib.Utils; 43 import com.android.settingslib.drawable.CircleFramedDrawable; 44 45 import java.io.File; 46 47 /** 48 * This class encapsulates a Dialog for editing the user nickname and photo. 49 */ 50 public class EditUserInfoController { 51 52 private static final String KEY_AWAITING_RESULT = "awaiting_result"; 53 private static final String KEY_SAVED_PHOTO = "pending_photo"; 54 55 private Dialog mEditUserInfoDialog; 56 private Bitmap mSavedPhoto; 57 private EditUserPhotoController mEditUserPhotoController; 58 private UserHandle mUser; 59 private UserManager mUserManager; 60 private boolean mWaitingForActivityResult = false; 61 62 public interface OnContentChangedCallback { onPhotoChanged(Drawable photo)63 public void onPhotoChanged(Drawable photo); onLabelChanged(CharSequence label)64 public void onLabelChanged(CharSequence label); 65 } 66 clear()67 public void clear() { 68 mEditUserPhotoController.removeNewUserPhotoBitmapFile(); 69 mEditUserInfoDialog = null; 70 mSavedPhoto = null; 71 } 72 getDialog()73 public Dialog getDialog() { 74 return mEditUserInfoDialog; 75 } 76 onRestoreInstanceState(Bundle icicle)77 public void onRestoreInstanceState(Bundle icicle) { 78 String pendingPhoto = icicle.getString(KEY_SAVED_PHOTO); 79 if (pendingPhoto != null) { 80 mSavedPhoto = EditUserPhotoController.loadNewUserPhotoBitmap(new File(pendingPhoto)); 81 } 82 mWaitingForActivityResult = icicle.getBoolean(KEY_AWAITING_RESULT, false); 83 } 84 onSaveInstanceState(Bundle outState)85 public void onSaveInstanceState(Bundle outState) { 86 if (mEditUserInfoDialog != null && mEditUserInfoDialog.isShowing() 87 && mEditUserPhotoController != null) { 88 // Bitmap cannot be stored into bundle because it may exceed parcel limit 89 // Store it in a temporary file instead 90 File file = mEditUserPhotoController.saveNewUserPhotoBitmap(); 91 if (file != null) { 92 outState.putString(KEY_SAVED_PHOTO, file.getPath()); 93 } 94 } 95 if (mWaitingForActivityResult) { 96 outState.putBoolean(KEY_AWAITING_RESULT, mWaitingForActivityResult); 97 } 98 } 99 startingActivityForResult()100 public void startingActivityForResult() { 101 mWaitingForActivityResult = true; 102 } 103 onActivityResult(int requestCode, int resultCode, Intent data)104 public void onActivityResult(int requestCode, int resultCode, Intent data) { 105 mWaitingForActivityResult = false; 106 107 if (mEditUserInfoDialog != null) { 108 mEditUserPhotoController.onActivityResult(requestCode, resultCode, data); 109 } 110 } 111 createDialog(final Fragment fragment, final Drawable currentUserIcon, final CharSequence currentUserName, int titleResId, final OnContentChangedCallback callback, UserHandle user)112 public Dialog createDialog(final Fragment fragment, final Drawable currentUserIcon, 113 final CharSequence currentUserName, 114 int titleResId, final OnContentChangedCallback callback, UserHandle user) { 115 Activity activity = fragment.getActivity(); 116 mUser = user; 117 if (mUserManager == null) { 118 mUserManager = activity.getSystemService(UserManager.class); 119 } 120 LayoutInflater inflater = activity.getLayoutInflater(); 121 View content = inflater.inflate(R.layout.edit_user_info_dialog_content, null); 122 123 UserInfo info = mUserManager.getUserInfo(mUser.getIdentifier()); 124 125 final EditText userNameView = (EditText) content.findViewById(R.id.user_name); 126 userNameView.setText(info.name); 127 128 final ImageView userPhotoView = (ImageView) content.findViewById(R.id.user_photo); 129 Drawable drawable = null; 130 if (mSavedPhoto != null) { 131 drawable = CircleFramedDrawable.getInstance(activity, mSavedPhoto); 132 } else { 133 drawable = currentUserIcon; 134 if (drawable == null) { 135 drawable = Utils.getUserIcon(activity, mUserManager, info); 136 } 137 } 138 userPhotoView.setImageDrawable(drawable); 139 mEditUserPhotoController = createEditUserPhotoController(fragment, userPhotoView, drawable); 140 mEditUserInfoDialog = new AlertDialog.Builder(activity) 141 .setTitle(R.string.profile_info_settings_title) 142 .setView(content) 143 .setCancelable(true) 144 .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { 145 @Override 146 public void onClick(DialogInterface dialog, int which) { 147 if (which == DialogInterface.BUTTON_POSITIVE) { 148 // Update the name if changed. 149 CharSequence userName = userNameView.getText(); 150 if (!TextUtils.isEmpty(userName)) { 151 if (currentUserName == null 152 || !userName.toString().equals(currentUserName.toString())) { 153 if (callback != null) { 154 callback.onLabelChanged(userName.toString()); 155 } 156 mUserManager.setUserName(mUser.getIdentifier(), 157 userName.toString()); 158 } 159 } 160 // Update the photo if changed. 161 Drawable drawable = mEditUserPhotoController.getNewUserPhotoDrawable(); 162 Bitmap bitmap = mEditUserPhotoController.getNewUserPhotoBitmap(); 163 if (drawable != null && bitmap != null 164 && !drawable.equals(currentUserIcon)) { 165 if (callback != null) { 166 callback.onPhotoChanged(drawable); 167 } 168 new AsyncTask<Void, Void, Void>() { 169 @Override 170 protected Void doInBackground(Void... params) { 171 mUserManager.setUserIcon(mUser.getIdentifier(), 172 mEditUserPhotoController.getNewUserPhotoBitmap()); 173 return null; 174 } 175 }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[]) null); 176 } 177 fragment.getActivity().removeDialog( 178 RestrictedProfileSettings.DIALOG_ID_EDIT_USER_INFO); 179 } 180 clear(); 181 } 182 }) 183 .setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() { 184 @Override 185 public void onClick(DialogInterface dialog, int which) { 186 clear(); 187 } 188 }) 189 .create(); 190 191 // Make sure the IME is up. 192 mEditUserInfoDialog.getWindow().setSoftInputMode( 193 WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE); 194 195 return mEditUserInfoDialog; 196 } 197 198 @VisibleForTesting createEditUserPhotoController(Fragment fragment, ImageView userPhotoView, Drawable drawable)199 EditUserPhotoController createEditUserPhotoController(Fragment fragment, 200 ImageView userPhotoView, Drawable drawable) { 201 return new EditUserPhotoController(fragment, userPhotoView, 202 mSavedPhoto, drawable, mWaitingForActivityResult); 203 } 204 } 205