AppRestrictionsFragment.java revision 5ee175051951d3a0bc1533aece69af520c295d37
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 17package com.android.settings.users; 18 19import android.app.Activity; 20import android.app.AppGlobals; 21import android.appwidget.AppWidgetManager; 22import android.content.BroadcastReceiver; 23import android.content.Context; 24import android.content.Intent; 25import android.content.RestrictionEntry; 26import android.content.pm.ApplicationInfo; 27import android.content.pm.IPackageManager; 28import android.content.pm.PackageInfo; 29import android.content.pm.PackageManager; 30import android.content.pm.PackageManager.NameNotFoundException; 31import android.content.pm.ResolveInfo; 32import android.content.pm.UserInfo; 33import android.graphics.Bitmap; 34import android.graphics.Color; 35import android.graphics.ColorFilter; 36import android.graphics.ColorMatrix; 37import android.graphics.ColorMatrixColorFilter; 38import android.graphics.drawable.BitmapDrawable; 39import android.graphics.drawable.ColorDrawable; 40import android.graphics.drawable.Drawable; 41import android.os.Bundle; 42import android.os.Parcelable; 43import android.os.RemoteException; 44import android.os.ServiceManager; 45import android.os.UserHandle; 46import android.os.UserManager; 47import android.preference.CheckBoxPreference; 48import android.preference.EditTextPreference; 49import android.preference.ListPreference; 50import android.preference.MultiSelectListPreference; 51import android.preference.Preference; 52import android.preference.PreferenceActivity; 53import android.preference.PreferenceCategory; 54import android.preference.Preference.OnPreferenceChangeListener; 55import android.preference.Preference.OnPreferenceClickListener; 56import android.preference.PreferenceGroup; 57import android.preference.SwitchPreference; 58import android.text.InputType; 59import android.text.TextUtils; 60import android.util.Log; 61import android.view.View; 62import android.view.View.OnClickListener; 63import android.view.ViewGroup; 64import android.widget.CompoundButton; 65import android.widget.CompoundButton.OnCheckedChangeListener; 66import android.widget.Switch; 67 68import com.android.settings.R; 69import com.android.settings.SelectableEditTextPreference; 70import com.android.settings.SettingsPreferenceFragment; 71 72import java.util.ArrayList; 73import java.util.Collection; 74import java.util.Collections; 75import java.util.Comparator; 76import java.util.HashMap; 77import java.util.HashSet; 78import java.util.List; 79import java.util.Map; 80import java.util.Set; 81import java.util.StringTokenizer; 82 83import libcore.util.CollectionUtils; 84 85public class AppRestrictionsFragment extends SettingsPreferenceFragment implements 86 OnPreferenceChangeListener, OnClickListener, OnPreferenceClickListener { 87 88 private static final String TAG = AppRestrictionsFragment.class.getSimpleName(); 89 90 private static final boolean DEBUG = false; 91 92 private static final String PKG_PREFIX = "pkg_"; 93 private static final String KEY_USER_INFO = "user_info"; 94 95 private UserManager mUserManager; 96 private UserHandle mUser; 97 98 private SelectableEditTextPreference mUserPreference; 99 private PreferenceGroup mAppList; 100 101 private static final int MAX_APP_RESTRICTIONS = 100; 102 103 private static final String DELIMITER = ";"; 104 105 /** Key for extra passed in from calling fragment for the userId of the user being edited */ 106 public static final String EXTRA_USER_ID = "user_id"; 107 108 /** Key for extra passed in from calling fragment to indicate if this is a newly created user */ 109 public static final String EXTRA_NEW_USER = "new_user"; 110 111 HashMap<String,Boolean> mSelectedPackages = new HashMap<String,Boolean>(); 112 private boolean mFirstTime = true; 113 private boolean mNewUser; 114 private boolean mAppListChanged; 115 116 private int mCustomRequestCode; 117 private HashMap<Integer, AppRestrictionsPreference> mCustomRequestMap = 118 new HashMap<Integer,AppRestrictionsPreference>(); 119 120 static class SelectableAppInfo { 121 String packageName; 122 CharSequence appName; 123 CharSequence activityName; 124 Drawable icon; 125 SelectableAppInfo masterEntry; 126 127 @Override 128 public String toString() { 129 return packageName + ": appName=" + appName + "; activityName=" + activityName 130 + "; icon=" + icon + "; masterEntry=" + masterEntry; 131 } 132 } 133 134 static class AppRestrictionsPreference extends SwitchPreference { 135 private boolean hasSettings; 136 private OnClickListener listener; 137 private ArrayList<RestrictionEntry> restrictions; 138 boolean panelOpen; 139 private boolean immutable; 140 List<Preference> childPreferences = new ArrayList<Preference>(); 141 private SelectableAppInfo appInfo; 142 private final ColorFilter grayscaleFilter; 143 144 AppRestrictionsPreference(Context context, OnClickListener listener) { 145 super(context); 146 setLayoutResource(R.layout.preference_app_restrictions); 147 this.listener = listener; 148 149 ColorMatrix colorMatrix = new ColorMatrix(); 150 colorMatrix.setSaturation(0f); 151 float[] matrix = colorMatrix.getArray(); 152 matrix[18] = 0.5f; 153 grayscaleFilter = new ColorMatrixColorFilter(colorMatrix); 154 } 155 156 private void setSettingsEnabled(boolean enable) { 157 hasSettings = enable; 158 } 159 160 @Override 161 public void setChecked(boolean checked) { 162 if (checked) { 163 getIcon().setColorFilter(null); 164 } else { 165 getIcon().setColorFilter(grayscaleFilter); 166 } 167 super.setChecked(checked); 168 } 169 170 void setRestrictions(ArrayList<RestrictionEntry> restrictions) { 171 this.restrictions = restrictions; 172 } 173 174 void setImmutable(boolean immutable) { 175 this.immutable = immutable; 176 } 177 178 boolean isImmutable() { 179 return immutable; 180 } 181 182 void setSelectableAppInfo(SelectableAppInfo appInfo) { 183 this.appInfo = appInfo; 184 } 185 186 RestrictionEntry getRestriction(String key) { 187 if (restrictions == null) return null; 188 for (RestrictionEntry entry : restrictions) { 189 if (entry.getKey().equals(key)) { 190 return entry; 191 } 192 } 193 return null; 194 } 195 196 ArrayList<RestrictionEntry> getRestrictions() { 197 return restrictions; 198 } 199 200 @Override 201 protected void onBindView(View view) { 202 super.onBindView(view); 203 204 View appRestrictionsSettings = view.findViewById(R.id.app_restrictions_settings); 205 appRestrictionsSettings.setVisibility(hasSettings ? View.VISIBLE : View.GONE); 206 view.findViewById(R.id.settings_divider).setVisibility( 207 hasSettings ? View.VISIBLE : View.GONE); 208 appRestrictionsSettings.setOnClickListener(listener); 209 appRestrictionsSettings.setTag(this); 210 211 View appRestrictionsPref = view.findViewById(R.id.app_restrictions_pref); 212 appRestrictionsPref.setOnClickListener(listener); 213 appRestrictionsPref.setTag(this); 214 215 ViewGroup widget = (ViewGroup) view.findViewById(android.R.id.widget_frame); 216 widget.setEnabled(!isImmutable()); 217 if (widget.getChildCount() > 0) { 218 final Switch switchView = (Switch) widget.getChildAt(0); 219 switchView.setEnabled(!isImmutable()); 220 switchView.setTag(this); 221 switchView.setOnCheckedChangeListener(new OnCheckedChangeListener() { 222 @Override 223 public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { 224 listener.onClick(switchView); 225 } 226 }); 227 } 228 } 229 } 230 231 @Override 232 public void onCreate(Bundle icicle) { 233 super.onCreate(icicle); 234 235 if (icicle != null) { 236 mNewUser = icicle.getBoolean(EXTRA_NEW_USER, false); 237 mUser = new UserHandle(icicle.getInt(EXTRA_USER_ID)); 238 } else { 239 Bundle args = getArguments(); 240 241 if (args.containsKey(EXTRA_USER_ID)) { 242 mUser = new UserHandle(args.getInt(EXTRA_USER_ID)); 243 } 244 mNewUser = args.getBoolean(EXTRA_NEW_USER, false); 245 } 246 mUserManager = (UserManager) getActivity().getSystemService(Context.USER_SERVICE); 247 addPreferencesFromResource(R.xml.app_restrictions); 248 mAppList = getPreferenceScreen(); 249 mUserPreference = (SelectableEditTextPreference) findPreference(KEY_USER_INFO); 250 mUserPreference.setOnPreferenceChangeListener(this); 251 mUserPreference.getEditText().setInputType( 252 InputType.TYPE_TEXT_VARIATION_NORMAL | InputType.TYPE_TEXT_FLAG_CAP_WORDS); 253 mUserPreference.setInitialSelectionMode( 254 SelectableEditTextPreference.SELECTION_SELECT_ALL); 255 setHasOptionsMenu(true); 256 } 257 258 @Override 259 public void onSaveInstanceState(Bundle outState) { 260 super.onSaveInstanceState(outState); 261 outState.putBoolean(EXTRA_NEW_USER, mNewUser); 262 outState.putInt(EXTRA_USER_ID, mUser.getIdentifier()); 263 } 264 265 public void onResume() { 266 super.onResume(); 267 mAppListChanged = false; 268 if (mFirstTime) { 269 mFirstTime = false; 270 populateApps(); 271 } 272 UserInfo info = mUserManager.getUserInfo(mUser.getIdentifier()); 273 mUserPreference.setTitle(info.name); 274 Bitmap userIcon = mUserManager.getUserIcon(mUser.getIdentifier()); 275 CircleFramedDrawable circularIcon = 276 CircleFramedDrawable.getInstance(this.getActivity(), userIcon); 277 mUserPreference.setIcon(circularIcon); 278 mUserPreference.setText(info.name); 279 } 280 281 public void onPause() { 282 super.onPause(); 283 if (mAppListChanged) { 284 new Thread() { 285 public void run() { 286 updateUserAppList(); 287 } 288 }.start(); 289 } 290 } 291 292 private void updateUserAppList() { 293 IPackageManager ipm = IPackageManager.Stub.asInterface( 294 ServiceManager.getService("package")); 295 for (Map.Entry<String,Boolean> entry : mSelectedPackages.entrySet()) { 296 if (entry.getValue()) { 297 // Enable selected apps 298 try { 299 ipm.installExistingPackageAsUser(entry.getKey(), mUser.getIdentifier()); 300 } catch (RemoteException re) { 301 } 302 } else { 303 // Blacklist all other apps, system or downloaded 304 try { 305 ipm.deletePackageAsUser(entry.getKey(), null, mUser.getIdentifier(), 306 PackageManager.DELETE_SYSTEM_APP); 307 } catch (RemoteException re) { 308 } 309 } 310 } 311 } 312 313 private void addSystemApps(List<SelectableAppInfo> visibleApps, Intent intent) { 314 final PackageManager pm = getActivity().getPackageManager(); 315 List<ResolveInfo> launchableApps = pm.queryIntentActivities(intent, 0); 316 for (ResolveInfo app : launchableApps) { 317 if (app.activityInfo != null && app.activityInfo.applicationInfo != null) { 318 int flags = app.activityInfo.applicationInfo.flags; 319 if ((flags & ApplicationInfo.FLAG_SYSTEM) != 0 320 || (flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) { 321 // System app 322 SelectableAppInfo info = new SelectableAppInfo(); 323 info.packageName = app.activityInfo.packageName; 324 info.appName = app.activityInfo.applicationInfo.loadLabel(pm); 325 info.icon = app.activityInfo.loadIcon(pm); 326 info.activityName = app.activityInfo.loadLabel(pm); 327 if (info.activityName == null) info.activityName = info.appName; 328 visibleApps.add(info); 329 } 330 } 331 } 332 } 333 334 private void populateApps() { 335 mAppList.setOrderingAsAdded(false); 336 List<SelectableAppInfo> visibleApps = new ArrayList<SelectableAppInfo>(); 337 // TODO: Do this asynchronously since it can be a long operation 338 final Context context = getActivity(); 339 PackageManager pm = context.getPackageManager(); 340 IPackageManager ipm = AppGlobals.getPackageManager(); 341 342 // Add launchers 343 Intent launcherIntent = new Intent(Intent.ACTION_MAIN); 344 launcherIntent.addCategory(Intent.CATEGORY_LAUNCHER); 345 addSystemApps(visibleApps, launcherIntent); 346 347 // Add widgets 348 Intent widgetIntent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE); 349 addSystemApps(visibleApps, widgetIntent); 350 351 List<ApplicationInfo> installedApps = pm.getInstalledApplications(0); 352 for (ApplicationInfo app : installedApps) { 353 if ((app.flags & ApplicationInfo.FLAG_SYSTEM) == 0 354 && (app.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) == 0) { 355 // Downloaded app 356 SelectableAppInfo info = new SelectableAppInfo(); 357 info.packageName = app.packageName; 358 info.appName = app.loadLabel(pm); 359 info.activityName = info.appName; 360 info.icon = app.loadIcon(pm); 361 visibleApps.add(info); 362 } 363 } 364 365 // Now check apps that are installed on target user 366 List<ApplicationInfo> userApps = null; 367 try { 368 userApps = ipm.getInstalledApplications( 369 0, mUser.getIdentifier()).getList(); 370 } catch (RemoteException re) { 371 } 372 373 if (userApps != null) { 374 for (ApplicationInfo app : userApps) { 375 if ((app.flags & ApplicationInfo.FLAG_SYSTEM) == 0 376 && (app.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) == 0) { 377 // Downloaded app 378 SelectableAppInfo info = new SelectableAppInfo(); 379 info.packageName = app.packageName; 380 info.appName = app.loadLabel(pm); 381 info.activityName = info.appName; 382 info.icon = app.loadIcon(pm); 383 visibleApps.add(info); 384 } 385 } 386 } 387 Collections.sort(visibleApps, new AppLabelComparator()); 388 389 // Remove dupes 390 for (int i = visibleApps.size() - 1; i > 1; i--) { 391 SelectableAppInfo info = visibleApps.get(i); 392 if (DEBUG) Log.i(TAG, info.toString()); 393 if (info.packageName.equals(visibleApps.get(i-1).packageName) 394 && info.activityName.equals(visibleApps.get(i-1).activityName)) { 395 visibleApps.remove(i); 396 } 397 } 398 399 // Establish master/slave relationship for entries that share a package name 400 HashMap<String,SelectableAppInfo> packageMap = new HashMap<String,SelectableAppInfo>(); 401 for (SelectableAppInfo info : visibleApps) { 402 if (packageMap.containsKey(info.packageName)) { 403 info.masterEntry = packageMap.get(info.packageName); 404 } else { 405 packageMap.put(info.packageName, info); 406 } 407 } 408 409 Intent restrictionsIntent = new Intent(Intent.ACTION_GET_RESTRICTION_ENTRIES); 410 final List<ResolveInfo> receivers = pm.queryBroadcastReceivers(restrictionsIntent, 0); 411 int i = 0; 412 if (visibleApps.size() > 0) { 413 for (SelectableAppInfo app : visibleApps) { 414 String packageName = app.packageName; 415 if (packageName == null) continue; 416 final boolean isSettingsApp = packageName.equals(getActivity().getPackageName()); 417 AppRestrictionsPreference p = new AppRestrictionsPreference(context, this); 418 final boolean hasSettings = resolveInfoListHasPackage(receivers, packageName); 419 p.setIcon(app.icon); 420 p.setChecked(false); 421 p.setTitle(app.activityName); 422 if (app.masterEntry != null) { 423 p.setSummary(getActivity().getString(R.string.user_restrictions_controlled_by, 424 app.masterEntry.activityName)); 425 } 426 p.setKey(PKG_PREFIX + packageName); 427 p.setSettingsEnabled(hasSettings || isSettingsApp); 428 p.setPersistent(false); 429 p.setOnPreferenceChangeListener(this); 430 p.setOnPreferenceClickListener(this); 431 PackageInfo pi = null; 432 try { 433 pi = pm.getPackageInfo(packageName, 0); 434 } catch (NameNotFoundException re) { 435 try { 436 pi = ipm.getPackageInfo(packageName, 0, mUser.getIdentifier()); 437 } catch (RemoteException e) { 438 } 439 } 440 if (pi != null && pi.requiredForAllUsers) { 441 p.setChecked(true); 442 p.setImmutable(true); 443 // If the app is required and has no restrictions, skip showing it 444 if (!hasSettings && !isSettingsApp) continue; 445 } else if (!mNewUser && appInfoListHasPackage(userApps, packageName)) { 446 p.setChecked(true); 447 } 448 if (pi.requiredAccountType != null && pi.restrictedAccountType == null) { 449 p.setChecked(false); 450 p.setImmutable(true); 451 p.setSummary(R.string.app_not_supported_in_limited); 452 } 453 if (app.masterEntry != null) { 454 p.setImmutable(true); 455 p.setChecked(mSelectedPackages.get(packageName)); 456 } 457 mAppList.addPreference(p); 458 if (isSettingsApp) { 459 p.setOrder(MAX_APP_RESTRICTIONS * 1); 460 } else { 461 p.setOrder(MAX_APP_RESTRICTIONS * (i + 2)); 462 } 463 p.setSelectableAppInfo(app); 464 mSelectedPackages.put(packageName, p.isChecked()); 465 mAppListChanged = true; 466 i++; 467 } 468 } 469 } 470 471 private class AppLabelComparator implements Comparator<SelectableAppInfo> { 472 473 @Override 474 public int compare(SelectableAppInfo lhs, SelectableAppInfo rhs) { 475 String lhsLabel = lhs.activityName.toString(); 476 String rhsLabel = rhs.activityName.toString(); 477 return lhsLabel.toLowerCase().compareTo(rhsLabel.toLowerCase()); 478 } 479 } 480 481 private boolean resolveInfoListHasPackage(List<ResolveInfo> receivers, String packageName) { 482 for (ResolveInfo info : receivers) { 483 if (info.activityInfo.packageName.equals(packageName)) { 484 return true; 485 } 486 } 487 return false; 488 } 489 490 private boolean appInfoListHasPackage(List<ApplicationInfo> apps, String packageName) { 491 for (ApplicationInfo info : apps) { 492 if (info.packageName.equals(packageName)) { 493 return true; 494 } 495 } 496 return false; 497 } 498 499 private void updateAllEntries(String prefKey, boolean checked) { 500 for (int i = 0; i < mAppList.getPreferenceCount(); i++) { 501 Preference pref = mAppList.getPreference(i); 502 if (pref instanceof AppRestrictionsPreference) { 503 if (prefKey.equals(pref.getKey())) { 504 ((AppRestrictionsPreference) pref).setChecked(checked); 505 } 506 } 507 } 508 } 509 510 @Override 511 public void onClick(View v) { 512 if (v.getTag() instanceof AppRestrictionsPreference) { 513 AppRestrictionsPreference pref = (AppRestrictionsPreference) v.getTag(); 514 if (v.getId() == R.id.app_restrictions_settings) { 515 toggleAppPanel(pref); 516 } else if (!pref.isImmutable()) { 517 pref.setChecked(!pref.isChecked()); 518 mSelectedPackages.put(pref.getKey().substring(PKG_PREFIX.length()), 519 pref.isChecked()); 520 mAppListChanged = true; 521 updateAllEntries(pref.getKey(), pref.isChecked()); 522 } 523 } 524 } 525 526 @Override 527 public boolean onPreferenceChange(Preference preference, Object newValue) { 528 String key = preference.getKey(); 529 if (key != null && key.contains(DELIMITER)) { 530 StringTokenizer st = new StringTokenizer(key, DELIMITER); 531 final String packageName = st.nextToken(); 532 final String restrictionKey = st.nextToken(); 533 AppRestrictionsPreference appPref = (AppRestrictionsPreference) 534 mAppList.findPreference(PKG_PREFIX+packageName); 535 ArrayList<RestrictionEntry> restrictions = appPref.getRestrictions(); 536 if (restrictions != null) { 537 for (RestrictionEntry entry : restrictions) { 538 if (entry.getKey().equals(restrictionKey)) { 539 switch (entry.getType()) { 540 case RestrictionEntry.TYPE_BOOLEAN: 541 entry.setSelectedState((Boolean) newValue); 542 break; 543 case RestrictionEntry.TYPE_CHOICE: 544 case RestrictionEntry.TYPE_CHOICE_LEVEL: 545 ListPreference listPref = (ListPreference) preference; 546 entry.setSelectedString((String) newValue); 547 String readable = findInArray(entry.getChoiceEntries(), 548 entry.getChoiceValues(), (String) newValue); 549 listPref.setSummary(readable); 550 break; 551 case RestrictionEntry.TYPE_MULTI_SELECT: 552 MultiSelectListPreference msListPref = 553 (MultiSelectListPreference) preference; 554 Set<String> set = (Set<String>) newValue; 555 String [] selectedValues = new String[set.size()]; 556 set.toArray(selectedValues); 557 entry.setAllSelectedStrings(selectedValues); 558 break; 559 default: 560 continue; 561 } 562 if (packageName.equals(getActivity().getPackageName())) { 563 RestrictionUtils.setRestrictions(getActivity(), restrictions, mUser); 564 } else { 565 mUserManager.setApplicationRestrictions(packageName, 566 RestrictionUtils.restrictionsToBundle(restrictions), 567 mUser); 568 } 569 break; 570 } 571 } 572 } 573 } else if (preference == mUserPreference) { 574 String userName = ((CharSequence) newValue).toString(); 575 if (!TextUtils.isEmpty(userName)) { 576 mUserManager.setUserName(mUser.getIdentifier(), userName); 577 mUserPreference.setTitle(userName); 578 } 579 } 580 return true; 581 } 582 583 private void toggleAppPanel(AppRestrictionsPreference preference) { 584 if (preference.getKey().startsWith(PKG_PREFIX)) { 585 if (preference.panelOpen) { 586 for (Preference p : preference.childPreferences) { 587 mAppList.removePreference(p); 588 } 589 preference.childPreferences.clear(); 590 } else { 591 String packageName = preference.getKey().substring(PKG_PREFIX.length()); 592 if (packageName.equals(getActivity().getPackageName())) { 593 // Settings, fake it by using user restrictions 594 ArrayList<RestrictionEntry> restrictions = RestrictionUtils.getRestrictions( 595 getActivity(), mUser); 596 onRestrictionsReceived(preference, packageName, restrictions); 597 } else { 598 Bundle oldEntries = 599 mUserManager.getApplicationRestrictions(packageName, mUser); 600 Intent intent = new Intent(Intent.ACTION_GET_RESTRICTION_ENTRIES); 601 intent.setPackage(packageName); 602 intent.putExtra(Intent.EXTRA_RESTRICTIONS_BUNDLE, oldEntries); 603 intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES); 604 getActivity().sendOrderedBroadcast(intent, null, 605 new RestrictionsResultReceiver(packageName, preference), 606 null, Activity.RESULT_OK, null, null); 607 } 608 } 609 preference.panelOpen = !preference.panelOpen; 610 } 611 } 612 613 class RestrictionsResultReceiver extends BroadcastReceiver { 614 615 private static final String CUSTOM_RESTRICTIONS_INTENT = Intent.EXTRA_RESTRICTIONS_INTENT; 616 String packageName; 617 AppRestrictionsPreference preference; 618 619 RestrictionsResultReceiver(String packageName, AppRestrictionsPreference preference) { 620 super(); 621 this.packageName = packageName; 622 this.preference = preference; 623 } 624 625 @Override 626 public void onReceive(Context context, Intent intent) { 627 Bundle results = getResultExtras(true); 628 final ArrayList<RestrictionEntry> restrictions = results.getParcelableArrayList( 629 Intent.EXTRA_RESTRICTIONS_LIST); 630 Intent restrictionsIntent = (Intent) results.getParcelable(CUSTOM_RESTRICTIONS_INTENT); 631 if (restrictions != null && restrictionsIntent == null) { 632 onRestrictionsReceived(preference, packageName, restrictions); 633 mUserManager.setApplicationRestrictions(packageName, 634 RestrictionUtils.restrictionsToBundle(restrictions), mUser); 635 } else if (restrictionsIntent != null) { 636 final Intent customIntent = restrictionsIntent; 637 customIntent.putExtra(Intent.EXTRA_RESTRICTIONS_BUNDLE, 638 RestrictionUtils.restrictionsToBundle(restrictions)); 639 Preference p = new Preference(context); 640 p.setTitle(R.string.app_restrictions_custom_label); 641 p.setOnPreferenceClickListener(new OnPreferenceClickListener() { 642 @Override 643 public boolean onPreferenceClick(Preference preference) { 644 int requestCode = generateCustomActivityRequestCode( 645 RestrictionsResultReceiver.this.preference); 646 AppRestrictionsFragment.this.startActivityForResult( 647 customIntent, requestCode); 648 return false; 649 } 650 }); 651 p.setPersistent(false); 652 p.setOrder(preference.getOrder() + 1); 653 preference.childPreferences.add(p); 654 mAppList.addPreference(p); 655 preference.setRestrictions(restrictions); 656 } 657 } 658 } 659 660 private void onRestrictionsReceived(AppRestrictionsPreference preference, String packageName, 661 ArrayList<RestrictionEntry> restrictions) { 662 // Non-custom-activity case - expand the restrictions in-place 663 final Context context = preference.getContext(); 664 int count = 1; 665 for (RestrictionEntry entry : restrictions) { 666 Preference p = null; 667 switch (entry.getType()) { 668 case RestrictionEntry.TYPE_BOOLEAN: 669 p = new CheckBoxPreference(context); 670 p.setTitle(entry.getTitle()); 671 p.setSummary(entry.getDescription()); 672 ((CheckBoxPreference)p).setChecked(entry.getSelectedState()); 673 break; 674 case RestrictionEntry.TYPE_CHOICE: 675 case RestrictionEntry.TYPE_CHOICE_LEVEL: 676 p = new ListPreference(context); 677 p.setTitle(entry.getTitle()); 678 String value = entry.getSelectedString(); 679 if (value == null) { 680 value = entry.getDescription(); 681 } 682 p.setSummary(findInArray(entry.getChoiceEntries(), entry.getChoiceValues(), 683 value)); 684 ((ListPreference)p).setEntryValues(entry.getChoiceValues()); 685 ((ListPreference)p).setEntries(entry.getChoiceEntries()); 686 ((ListPreference)p).setValue(value); 687 ((ListPreference)p).setDialogTitle(entry.getTitle()); 688 break; 689 case RestrictionEntry.TYPE_MULTI_SELECT: 690 p = new MultiSelectListPreference(context); 691 p.setTitle(entry.getTitle()); 692 ((MultiSelectListPreference)p).setEntryValues(entry.getChoiceValues()); 693 ((MultiSelectListPreference)p).setEntries(entry.getChoiceEntries()); 694 HashSet<String> set = new HashSet<String>(); 695 for (String s : entry.getAllSelectedStrings()) { 696 set.add(s); 697 } 698 ((MultiSelectListPreference)p).setValues(set); 699 ((MultiSelectListPreference)p).setDialogTitle(entry.getTitle()); 700 break; 701 case RestrictionEntry.TYPE_NULL: 702 default: 703 } 704 if (p != null) { 705 p.setPersistent(false); 706 p.setOrder(preference.getOrder() + count); 707 // Store the restrictions key string as a key for the preference 708 p.setKey(preference.getKey().substring(PKG_PREFIX.length()) + DELIMITER 709 + entry.getKey()); 710 mAppList.addPreference(p); 711 p.setOnPreferenceChangeListener(AppRestrictionsFragment.this); 712 preference.childPreferences.add(p); 713 count++; 714 } 715 } 716 preference.setRestrictions(restrictions); 717 } 718 719 /** 720 * Generates a request code that is stored in a map to retrieve the associated 721 * AppRestrictionsPreference. 722 * @param preference 723 * @return 724 */ 725 private int generateCustomActivityRequestCode(AppRestrictionsPreference preference) { 726 mCustomRequestCode++; 727 mCustomRequestMap.put(mCustomRequestCode, preference); 728 return mCustomRequestCode; 729 } 730 731 @Override 732 public void onActivityResult(int requestCode, int resultCode, Intent data) { 733 super.onActivityResult(requestCode, resultCode, data); 734 735 Log.i(TAG, "Got activity resultCode=" + resultCode + ", requestCode=" 736 + requestCode + ", data=" + data); 737 738 AppRestrictionsPreference pref = mCustomRequestMap.get(requestCode); 739 if (pref == null) { 740 Log.w(TAG, "Unknown requestCode " + requestCode); 741 return; 742 } 743 744 if (resultCode == Activity.RESULT_OK) { 745 ArrayList<RestrictionEntry> list = 746 data.getParcelableArrayListExtra(Intent.EXTRA_RESTRICTIONS_LIST); 747 if (list != null) { 748 // If there's a valid result, persist it to the user manager. 749 String packageName = pref.getKey().substring(PKG_PREFIX.length()); 750 pref.setRestrictions(list); 751 mUserManager.setApplicationRestrictions(packageName, 752 RestrictionUtils.restrictionsToBundle(list), mUser); 753 } 754 toggleAppPanel(pref); 755 } 756 // Remove request from the map 757 mCustomRequestMap.remove(requestCode); 758 } 759 760 private String findInArray(String[] choiceEntries, String[] choiceValues, 761 String selectedString) { 762 for (int i = 0; i < choiceValues.length; i++) { 763 if (choiceValues[i].equals(selectedString)) { 764 return choiceEntries[i]; 765 } 766 } 767 return selectedString; 768 } 769 770 @Override 771 public boolean onPreferenceClick(Preference preference) { 772 if (preference.getKey().startsWith(PKG_PREFIX)) { 773 AppRestrictionsPreference arp = (AppRestrictionsPreference) preference; 774 if (!arp.isImmutable()) { 775 arp.setChecked(!arp.isChecked()); 776 mSelectedPackages.put(arp.getKey().substring(PKG_PREFIX.length()), arp.isChecked()); 777 updateAllEntries(arp.getKey(), arp.isChecked()); 778 mAppListChanged = true; 779 } 780 return true; 781 } 782 return false; 783 } 784} 785