1/* 2 * Copyright (C) 2012 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 17package com.android.settings.users; 18 19import android.app.AlertDialog; 20import android.app.Dialog; 21import android.content.DialogInterface; 22import android.content.Intent; 23import android.content.pm.ApplicationInfo; 24import android.content.pm.IPackageManager; 25import android.content.pm.PackageInfo; 26import android.content.pm.PackageManager; 27import android.content.pm.ResolveInfo; 28import android.content.pm.UserInfo; 29import android.graphics.drawable.Drawable; 30import android.net.Uri; 31import android.os.Bundle; 32import android.os.RemoteException; 33import android.os.ServiceManager; 34import android.os.SystemProperties; 35import android.preference.CheckBoxPreference; 36import android.preference.EditTextPreference; 37import android.preference.Preference; 38import android.preference.PreferenceGroup; 39import android.text.TextUtils; 40import android.util.Log; 41import android.view.Menu; 42import android.view.MenuInflater; 43import android.view.MenuItem; 44 45import com.android.settings.DialogCreatable; 46import com.android.settings.R; 47import com.android.settings.SettingsPreferenceFragment; 48 49import java.util.HashMap; 50import java.util.List; 51 52public class UserDetailsSettings extends SettingsPreferenceFragment 53 implements Preference.OnPreferenceChangeListener, DialogCreatable { 54 55 private static final String TAG = "UserDetailsSettings"; 56 57 private static final int MENU_REMOVE_USER = Menu.FIRST; 58 private static final int DIALOG_CONFIRM_REMOVE = 1; 59 60 private static final String KEY_USER_NAME = "user_name"; 61 private static final String KEY_INSTALLED_APPS = "market_apps_category"; 62 private static final String KEY_SYSTEM_APPS = "system_apps_category"; 63 public static final String EXTRA_USER_ID = "user_id"; 64 65 private static final String[] SYSTEM_APPS = { 66 "com.google.android.browser", 67 "com.google.android.gm", 68 "com.google.android.youtube" 69 }; 70 71 static class AppState { 72 boolean dirty; 73 boolean enabled; 74 75 AppState(boolean enabled) { 76 this.enabled = enabled; 77 } 78 } 79 80 private HashMap<String, AppState> mAppStates = new HashMap<String, AppState>(); 81 private PreferenceGroup mSystemAppGroup; 82 private PreferenceGroup mInstalledAppGroup; 83 private EditTextPreference mNamePref; 84 85 private IPackageManager mIPm; 86 private PackageManager mPm; 87 private int mUserId; 88 private boolean mNewUser; 89 90 @Override 91 public void onCreate(Bundle icicle) { 92 super.onCreate(icicle); 93 addPreferencesFromResource(R.xml.user_details); 94 Bundle args = getArguments(); 95 mNewUser = args == null || args.getInt(EXTRA_USER_ID, -1) == -1; 96 mUserId = mNewUser ? -1 : args.getInt(EXTRA_USER_ID, -1); 97 mIPm = IPackageManager.Stub.asInterface(ServiceManager.getService("package")); 98 99 if (mUserId == -1) { 100 try { 101 mUserId = mIPm.createUser(getString(R.string.user_new_user_name), 0).id; 102 } catch (RemoteException re) { 103 } 104 } 105 mSystemAppGroup = (PreferenceGroup) findPreference(KEY_SYSTEM_APPS); 106 mInstalledAppGroup = (PreferenceGroup) findPreference(KEY_INSTALLED_APPS); 107 mNamePref = (EditTextPreference) findPreference(KEY_USER_NAME); 108 mNamePref.setOnPreferenceChangeListener(this); 109 110 setHasOptionsMenu(true); 111 } 112 113 @Override 114 public void onResume() { 115 super.onResume(); 116 mPm = getActivity().getPackageManager(); 117 if (mUserId > 0) { 118 initExistingUser(); 119 } else { 120 initNewUser(); 121 } 122 refreshApps(); 123 } 124 125 @Override 126 public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { 127 MenuItem addAccountItem = menu.add(0, MENU_REMOVE_USER, 0, 128 mNewUser ? R.string.user_discard_user_menu : R.string.user_remove_user_menu); 129 addAccountItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM 130 | MenuItem.SHOW_AS_ACTION_WITH_TEXT); 131 } 132 133 @Override 134 public boolean onOptionsItemSelected(MenuItem item) { 135 final int itemId = item.getItemId(); 136 if (itemId == MENU_REMOVE_USER) { 137 onRemoveUserClicked(); 138 return true; 139 } else { 140 return super.onOptionsItemSelected(item); 141 } 142 } 143 144 private void initExistingUser() { 145 List<UserInfo> users = mPm.getUsers(); 146 UserInfo foundUser = null; 147 for (UserInfo user : users) { 148 if (user.id == mUserId) { 149 foundUser = user; 150 break; 151 } 152 } 153 if (foundUser != null) { 154 mNamePref.setSummary(foundUser.name); 155 mNamePref.setText(foundUser.name); 156 } 157 } 158 159 private void initNewUser() { 160 // TODO: Check if there's already a "New user" and localize 161 mNamePref.setText(getString(R.string.user_new_user_name)); 162 mNamePref.setSummary(getString(R.string.user_new_user_name)); 163 } 164 165 private void onRemoveUserClicked() { 166 if (mNewUser) { 167 removeUserNow(); 168 } else { 169 showDialog(DIALOG_CONFIRM_REMOVE); 170 } 171 } 172 173 private void removeUserNow() { 174 try { 175 mIPm.removeUser(mUserId); 176 } catch (RemoteException re) { 177 // Couldn't remove user. Shouldn't happen 178 Log.e(TAG, "Couldn't remove user " + mUserId + "\n" + re); 179 } 180 finish(); 181 } 182 183 private void insertAppInfo(PreferenceGroup group, HashMap<String, AppState> appStateMap, 184 PackageInfo info, boolean defaultState) { 185 if (info != null) { 186 String pkgName = info.packageName; 187 String name = info.applicationInfo.loadLabel(mPm).toString(); 188 Drawable icon = info.applicationInfo.loadIcon(mPm); 189 AppState appState = appStateMap.get(info.packageName); 190 boolean enabled = appState == null ? defaultState : appState.enabled; 191 CheckBoxPreference appPref = new CheckBoxPreference(getActivity()); 192 appPref.setTitle(name != null ? name : pkgName); 193 appPref.setIcon(icon); 194 appPref.setChecked(enabled); 195 appPref.setKey(pkgName); 196 appPref.setPersistent(false); 197 appPref.setOnPreferenceChangeListener(this); 198 group.addPreference(appPref); 199 } 200 } 201 202 private void refreshApps() { 203 mSystemAppGroup.removeAll(); 204 mInstalledAppGroup.removeAll(); 205 206 boolean firstTime = mAppStates.isEmpty(); 207 208 final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null); 209 mainIntent.addCategory(Intent.CATEGORY_LAUNCHER); 210 List<ResolveInfo> apps = mPm.queryIntentActivities(mainIntent, 0); 211 212 for (ResolveInfo resolveInfo : apps) { 213 PackageInfo info; 214 try { 215 info = mIPm.getPackageInfo(resolveInfo.activityInfo.packageName, 216 0 /* flags */, 217 mUserId < 0 ? 0 : mUserId); 218 } catch (RemoteException re) { 219 continue; 220 } 221 if (firstTime) { 222 mAppStates.put(resolveInfo.activityInfo.packageName, 223 new AppState(info.applicationInfo.enabled)); 224 } 225 if ((info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) { 226 if (mSystemAppGroup.findPreference(info.packageName) != null) { 227 continue; 228 } 229 insertAppInfo(mSystemAppGroup, mAppStates, info, false); 230 } else { 231 if (mInstalledAppGroup.findPreference(info.packageName) != null) { 232 continue; 233 } 234 insertAppInfo(mInstalledAppGroup, mAppStates, info, false); 235 } 236 } 237 } 238 239 @Override 240 public boolean onPreferenceChange(Preference preference, Object newValue) { 241 if (preference instanceof CheckBoxPreference) { 242 String packageName = preference.getKey(); 243 int newState = ((Boolean) newValue) ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED 244 : PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER; 245 try { 246 mIPm.setApplicationEnabledSetting(packageName, newState, 0, mUserId); 247 } catch (RemoteException re) { 248 Log.e(TAG, "Unable to change enabled state of package " + packageName 249 + " for user " + mUserId); 250 } 251 } else if (preference == mNamePref) { 252 String name = (String) newValue; 253 if (TextUtils.isEmpty(name)) { 254 return false; 255 } 256 try { 257 mIPm.updateUserName(mUserId, (String) newValue); 258 mNamePref.setSummary((String) newValue); 259 } catch (RemoteException re) { 260 return false; 261 } 262 } 263 return true; 264 } 265 266 @Override 267 public Dialog onCreateDialog(int dialogId) { 268 switch (dialogId) { 269 case DIALOG_CONFIRM_REMOVE: 270 return new AlertDialog.Builder(getActivity()) 271 .setTitle(R.string.user_confirm_remove_title) 272 .setMessage(R.string.user_confirm_remove_message) 273 .setPositiveButton(android.R.string.ok, 274 new DialogInterface.OnClickListener() { 275 public void onClick(DialogInterface dialog, int which) { 276 removeUserNow(); 277 } 278 }) 279 .setNegativeButton(android.R.string.cancel, null) 280 .create(); 281 default: 282 return null; 283 } 284 } 285} 286