Application restrictions UI
Refactored User Settings UI to have two types of users.
Display a list of apps to select.
Edit user restrictions.
Handle saving and updating RestrictionEntry items via
User Manager.
Change-Id: I3ad5aa71d5ef66dffd39e17ba0556f075ac10a0f
diff --git a/src/com/android/settings/Settings.java b/src/com/android/settings/Settings.java
index 962d042..be8e1cc 100644
--- a/src/com/android/settings/Settings.java
+++ b/src/com/android/settings/Settings.java
@@ -22,6 +22,7 @@
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.RestrictionEntry;
import android.content.SharedPreferences;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
@@ -56,6 +57,7 @@
import com.android.settings.accounts.ManageAccountsSettings;
import com.android.settings.bluetooth.BluetoothEnabler;
import com.android.settings.bluetooth.BluetoothSettings;
+import com.android.settings.users.RestrictionsReceiver;
import com.android.settings.wfd.WifiDisplaySettings;
import com.android.settings.wifi.WifiEnabler;
import com.android.settings.wifi.WifiSettings;
@@ -133,12 +135,16 @@
private Header mLastHeader;
private boolean mListeningToAccountUpdates;
+ private List<RestrictionEntry> mAppRestrictions;
+
@Override
protected void onCreate(Bundle savedInstanceState) {
if (getIntent().hasExtra(EXTRA_UI_OPTIONS)) {
getWindow().setUiOptions(getIntent().getIntExtra(EXTRA_UI_OPTIONS, 0));
}
+ mAppRestrictions = getApplicationRestrictions();
+
mAuthenticatorHelper = new AuthenticatorHelper();
mAuthenticatorHelper.updateAuthDescriptions(this);
mAuthenticatorHelper.onAccountsUpdated(this, null);
@@ -408,7 +414,6 @@
DevelopmentSettings.PREF_SHOW,
android.os.Build.TYPE.equals("eng"));
int i = 0;
-
mHeaderIndexMap.clear();
while (i < target.size()) {
Header header = target.get(i);
@@ -450,6 +455,15 @@
if (!showDev) {
target.remove(i);
}
+ } else if (id == R.id.application_settings) {
+ if (mAppRestrictions != null) {
+ for (RestrictionEntry entry : mAppRestrictions) {
+ if (entry.key.equals(RestrictionsReceiver.KEY_ENABLE_APPS)
+ && !entry.getBooleanValue()) {
+ target.remove(i);
+ }
+ }
+ }
}
if (i < target.size() && target.get(i) == header
@@ -828,4 +842,5 @@
public static class WifiDisplaySettingsActivity extends Settings { /* empty */ }
public static class DreamSettingsActivity extends Settings { /* empty */ }
public static class NotificationStationActivity extends Settings { /* empty */ }
+ public static class UserSettingsActivity extends Settings { /* empty */ }
}
diff --git a/src/com/android/settings/users/AppRestrictionsFragment.java b/src/com/android/settings/users/AppRestrictionsFragment.java
new file mode 100644
index 0000000..9757f30
--- /dev/null
+++ b/src/com/android/settings/users/AppRestrictionsFragment.java
@@ -0,0 +1,463 @@
+/*
+ * Copyright (C) 2013 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.users;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.RestrictionEntry;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.ResolveInfo;
+import android.content.pm.UserInfo;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.preference.CheckBoxPreference;
+import android.preference.EditTextPreference;
+import android.preference.ListPreference;
+import android.preference.MultiSelectListPreference;
+import android.preference.Preference;
+import android.preference.PreferenceActivity;
+import android.preference.PreferenceCategory;
+import android.preference.Preference.OnPreferenceChangeListener;
+import android.preference.Preference.OnPreferenceClickListener;
+import android.preference.PreferenceGroup;
+import android.preference.SwitchPreference;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.ViewGroup;
+import android.widget.CompoundButton;
+import android.widget.CompoundButton.OnCheckedChangeListener;
+import android.widget.Switch;
+
+import com.android.settings.R;
+import com.android.settings.SettingsPreferenceFragment;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.StringTokenizer;
+
+import libcore.util.CollectionUtils;
+
+public class AppRestrictionsFragment extends SettingsPreferenceFragment implements
+ OnPreferenceChangeListener, OnClickListener, OnPreferenceClickListener {
+
+ private static final String TAG = AppRestrictionsFragment.class.getSimpleName();
+
+ private static final String PKG_PREFIX = "pkg_";
+ private static final String KEY_USER_INFO = "user_info";
+
+ private UserManager mUserManager;
+ private UserHandle mUser;
+
+ private EditTextPreference mUserPreference;
+ private PreferenceGroup mAppList;
+
+ private static final int MAX_APP_RESTRICTIONS = 100;
+
+ private static final String DELIMITER = ";";
+ private List<ResolveInfo> mApps;
+ HashMap<String,Boolean> mSelectedPackages = new HashMap<String,Boolean>();
+ private boolean mFirstTime = true;
+ private boolean mNewUser;
+
+ public static class Activity extends PreferenceActivity {
+ @Override
+ public Intent getIntent() {
+ Intent modIntent = new Intent(super.getIntent());
+ modIntent.putExtra(EXTRA_SHOW_FRAGMENT, AppRestrictionsFragment.class.getName());
+ modIntent.putExtra(EXTRA_NO_HEADERS, true);
+ return modIntent;
+ }
+ }
+
+ static class AppRestrictionsPreference extends SwitchPreference {
+ private boolean hasSettings;
+ private OnClickListener listener;
+ private ArrayList<RestrictionEntry> restrictions;
+ boolean panelOpen;
+ private boolean required;
+ List<Preference> childPreferences = new ArrayList<Preference>();
+
+ AppRestrictionsPreference(Context context, OnClickListener listener) {
+ super(context);
+ setLayoutResource(R.layout.preference_app_restrictions);
+ this.listener = listener;
+ }
+
+ private void setSettingsEnabled(boolean enable) {
+ hasSettings = enable;
+ }
+
+ void setRestrictions(ArrayList<RestrictionEntry> restrictions) {
+ this.restrictions = restrictions;
+ }
+
+ void setRequired(boolean required) {
+ this.required = required;
+ }
+
+ boolean isRequired() {
+ return required;
+ }
+
+ RestrictionEntry getRestriction(String key) {
+ if (restrictions == null) return null;
+ for (RestrictionEntry entry : restrictions) {
+ if (entry.key.equals(key)) {
+ return entry;
+ }
+ }
+ return null;
+ }
+
+ ArrayList<RestrictionEntry> getRestrictions() {
+ return restrictions;
+ }
+
+ @Override
+ protected void onBindView(View view) {
+ super.onBindView(view);
+
+ View appRestrictionsSettings = view.findViewById(R.id.app_restrictions_settings);
+ appRestrictionsSettings.setVisibility(hasSettings ? View.VISIBLE : View.GONE);
+ view.findViewById(R.id.settings_divider).setVisibility(
+ hasSettings ? View.VISIBLE : View.GONE);
+ appRestrictionsSettings.setOnClickListener(listener);
+ appRestrictionsSettings.setTag(this);
+
+ View appRestrictionsPref = view.findViewById(R.id.app_restrictions_pref);
+ appRestrictionsPref.setOnClickListener(listener);
+ appRestrictionsPref.setTag(this);
+
+ ViewGroup widget = (ViewGroup) view.findViewById(android.R.id.widget_frame);
+ widget.setEnabled(!isRequired());
+ if (widget.getChildCount() > 0) {
+ final Switch switchView = (Switch) widget.getChildAt(0);
+ switchView.setEnabled(!isRequired());
+ switchView.setTag(this);
+ switchView.setOnCheckedChangeListener(new OnCheckedChangeListener() {
+ @Override
+ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+ listener.onClick(switchView);
+ }
+ });
+ }
+ }
+ }
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ mUserManager = (UserManager) getActivity().getSystemService(Context.USER_SERVICE);
+ addPreferencesFromResource(R.xml.app_restrictions);
+ mAppList = getPreferenceScreen();
+ mUserPreference = (EditTextPreference) findPreference(KEY_USER_INFO);
+ mUserPreference.setOnPreferenceChangeListener(this);
+ setHasOptionsMenu(true);
+ }
+
+ void setUser(UserHandle user, boolean newUser) {
+ mUser = user;
+ mNewUser = newUser;
+ }
+
+ public void onResume() {
+ super.onResume();
+ if (mFirstTime) {
+ mFirstTime = false;
+ populateApps();
+ }
+ UserInfo info = mUserManager.getUserInfo(mUser.getIdentifier());
+ mUserPreference.setTitle(info.name);
+ mUserPreference.setIcon(
+ new BitmapDrawable(mUserManager.getUserIcon(mUser.getIdentifier())));
+ mUserPreference.setText(info.name);
+ }
+
+ private void populateApps() {
+ mAppList.setOrderingAsAdded(false);
+
+ // TODO: Do this asynchronously since it can be a long operation
+ final Context context = getActivity();
+ PackageManager pm = context.getPackageManager();
+ Intent launcherIntent = new Intent(Intent.ACTION_MAIN);
+ launcherIntent.addCategory(Intent.CATEGORY_LAUNCHER);
+ mApps = pm.queryIntentActivities(launcherIntent, 0);
+ Collections.sort(mApps, new AppLabelComparator(pm));
+
+ Intent restrictionsIntent = new Intent(Intent.ACTION_GET_RESTRICTION_ENTRIES);
+ final List<ResolveInfo> receivers = pm.queryBroadcastReceivers(restrictionsIntent, 0);
+ final List<ResolveInfo> existingApps = pm.queryIntentActivitiesAsUser(launcherIntent,
+ 0, mUser.getIdentifier());
+ int i = 0;
+ if (receivers != null && receivers.size() > 0) {
+ for (ResolveInfo app : mApps) {
+ if (app.activityInfo == null || app.activityInfo.packageName == null) continue;
+ String packageName = app.activityInfo.packageName;
+ Drawable icon = app.loadIcon(pm);
+ CharSequence label = app.loadLabel(pm);
+ AppRestrictionsPreference p = new AppRestrictionsPreference(context, this);
+ p.setIcon(icon);
+ p.setTitle(label);
+ p.setKey(PKG_PREFIX + packageName);
+ p.setSettingsEnabled(hasPackage(receivers, packageName));
+ p.setPersistent(false);
+ p.setOnPreferenceChangeListener(this);
+ p.setOnPreferenceClickListener(this);
+ try {
+ PackageInfo pi = pm.getPackageInfo(packageName, 0);
+ if (pi.requiredForAllUsers) {
+ p.setChecked(true);
+ p.setRequired(true);
+ } else if (!mNewUser && hasPackage(existingApps, packageName)) {
+ p.setChecked(true);
+ }
+ } catch (NameNotFoundException re) {
+ // This would be bad
+ }
+
+ mAppList.addPreference(p);
+ if (packageName.equals(getActivity().getPackageName())) {
+ p.setOrder(MAX_APP_RESTRICTIONS * 1);
+ } else {
+ p.setOrder(MAX_APP_RESTRICTIONS * (i + 2));
+ }
+ mSelectedPackages.put(packageName, p.isChecked());
+ i++;
+ }
+ }
+ }
+
+ private class AppLabelComparator implements Comparator<ResolveInfo> {
+
+ PackageManager pm;
+
+ private AppLabelComparator(PackageManager pm) {
+ this.pm = pm;
+ }
+
+ private CharSequence getLabel(ResolveInfo info) {
+ // TODO: Optimize this with a cache
+ return info.activityInfo.loadLabel(pm);
+ }
+
+ @Override
+ public int compare(ResolveInfo lhs, ResolveInfo rhs) {
+ String lhsLabel = getLabel(lhs).toString();
+ String rhsLabel = getLabel(rhs).toString();
+ return lhsLabel.compareTo(rhsLabel);
+ }
+ }
+
+ private boolean hasPackage(List<ResolveInfo> receivers, String packageName) {
+ for (ResolveInfo info : receivers) {
+ if (info.activityInfo.packageName.equals(packageName)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public void onClick(View v) {
+ if (v.getTag() instanceof AppRestrictionsPreference) {
+ AppRestrictionsPreference pref = (AppRestrictionsPreference) v.getTag();
+ if (v.getId() == R.id.app_restrictions_settings) {
+ handleSettingsClick(pref);
+ } else if (!pref.isRequired()) {
+ pref.setChecked(!pref.isChecked());
+ mSelectedPackages.put(pref.getKey().substring(PKG_PREFIX.length()),
+ pref.isChecked());
+ }
+ }
+ }
+
+ @Override
+ public boolean onPreferenceChange(Preference preference, Object newValue) {
+ String key = preference.getKey();
+ if (key != null && key.contains(DELIMITER)) {
+ StringTokenizer st = new StringTokenizer(key, DELIMITER);
+ final String packageName = st.nextToken();
+ final String restrictionKey = st.nextToken();
+ AppRestrictionsPreference appPref = (AppRestrictionsPreference)
+ mAppList.findPreference(PKG_PREFIX+packageName);
+ ArrayList<RestrictionEntry> restrictions = appPref.getRestrictions();
+ if (restrictions != null) {
+ for (RestrictionEntry entry : restrictions) {
+ if (entry.key.equals(restrictionKey)) {
+ switch (entry.type) {
+ case RestrictionEntry.TYPE_BOOLEAN:
+ entry.setValue((Boolean) newValue);
+ break;
+ case RestrictionEntry.TYPE_CHOICE:
+ case RestrictionEntry.TYPE_CHOICE_LEVEL:
+ ListPreference listPref = (ListPreference) preference;
+ entry.setValue((String) newValue);
+ for (int i = 0; i < listPref.getEntryValues().length; i++) {
+ if (entry.values[i].equals(newValue)) {
+ listPref.setSummary(entry.choices[i]);
+ break;
+ }
+ }
+ break;
+ case RestrictionEntry.TYPE_MULTI_SELECT:
+ MultiSelectListPreference msListPref =
+ (MultiSelectListPreference) preference;
+ Set<String> set = (Set<String>) newValue;
+ String [] selectedValues = new String[set.size()];
+ set.toArray(selectedValues);
+ entry.setMultipleValues(selectedValues);
+ break;
+ default:
+ continue;
+ }
+ mUserManager.setApplicationRestrictions(packageName, restrictions,
+ mUser);
+ break;
+ }
+ }
+ }
+ } else if (preference == mUserPreference) {
+ String userName = ((CharSequence) newValue).toString();
+ if (!TextUtils.isEmpty(userName)) {
+ mUserManager.setUserName(mUser.getIdentifier(), userName);
+ mUserPreference.setTitle(userName);
+ }
+ }
+ return true;
+ }
+
+ private void handleSettingsClick(AppRestrictionsPreference preference) {
+ if (preference.getKey().startsWith(PKG_PREFIX)) {
+ if (preference.panelOpen) {
+ for (Preference p : preference.childPreferences) {
+ mAppList.removePreference(p);
+ }
+ preference.childPreferences.clear();
+ } else {
+ String packageName = preference.getKey().substring(PKG_PREFIX.length());
+ List<RestrictionEntry> oldEntries =
+ mUserManager.getApplicationRestrictions(packageName, mUser);
+ Intent intent = new Intent(Intent.ACTION_GET_RESTRICTION_ENTRIES);
+ intent.putParcelableArrayListExtra(Intent.EXTRA_RESTRICTIONS,
+ new ArrayList<RestrictionEntry>(oldEntries));
+ getActivity().sendOrderedBroadcast(intent, null,
+ new RestrictionsResultReceiver(packageName, preference),
+ null, Activity.RESULT_OK, null, null);
+ }
+ preference.panelOpen = !preference.panelOpen;
+ }
+ }
+
+ class RestrictionsResultReceiver extends BroadcastReceiver {
+
+ String packageName;
+ AppRestrictionsPreference preference;
+
+ RestrictionsResultReceiver(String packageName, AppRestrictionsPreference preference) {
+ super();
+ this.packageName = packageName;
+ this.preference = preference;
+ }
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ ArrayList<RestrictionEntry> restrictions = getResultExtras(true).getParcelableArrayList(
+ Intent.EXTRA_RESTRICTIONS);
+ if (restrictions != null) {
+ int count = 1;
+ for (RestrictionEntry entry : restrictions) {
+ Preference p = null;
+ switch (entry.type) {
+ case RestrictionEntry.TYPE_BOOLEAN:
+ p = new CheckBoxPreference(context);
+ p.setTitle(entry.title);
+ p.setSummary(entry.description);
+ ((CheckBoxPreference)p).setChecked(entry.getBooleanValue());
+ break;
+ case RestrictionEntry.TYPE_CHOICE:
+ case RestrictionEntry.TYPE_CHOICE_LEVEL:
+ p = new ListPreference(context);
+ p.setTitle(entry.title);
+ String value = entry.getStringValue();
+ if (value == null) {
+ value = entry.description;
+ }
+ p.setSummary(value);
+ ((ListPreference)p).setEntryValues(entry.values);
+ ((ListPreference)p).setEntries(entry.choices);
+ ((ListPreference)p).setValue(entry.getStringValue());
+ break;
+ case RestrictionEntry.TYPE_MULTI_SELECT:
+ p = new MultiSelectListPreference(context);
+ p.setTitle(entry.title);
+ ((MultiSelectListPreference)p).setEntryValues(entry.values);
+ ((MultiSelectListPreference)p).setEntries(entry.choices);
+ HashSet<String> set = new HashSet<String>();
+ for (String s : entry.getMultipleValues()) {
+ set.add(s);
+ }
+ ((MultiSelectListPreference)p).setValues(set);
+ break;
+ case RestrictionEntry.TYPE_NULL:
+ default:
+ }
+ if (p != null) {
+ p.setPersistent(false);
+ p.setOrder(preference.getOrder() + count);
+ // Store the restrictions key string as a key for the preference
+ p.setKey(preference.getKey().substring(PKG_PREFIX.length()) + DELIMITER
+ + entry.key);
+ mAppList.addPreference(p);
+ p.setOnPreferenceChangeListener(AppRestrictionsFragment.this);
+ preference.childPreferences.add(p);
+ count++;
+ }
+ }
+ preference.setRestrictions(restrictions);
+ }
+ mUserManager.setApplicationRestrictions(packageName, restrictions, mUser);
+ }
+ }
+
+ @Override
+ public boolean onPreferenceClick(Preference preference) {
+ if (preference.getKey().startsWith(PKG_PREFIX)) {
+ AppRestrictionsPreference arp = (AppRestrictionsPreference) preference;
+ if (!arp.isRequired()) {
+ arp.setChecked(!arp.isChecked());
+ mSelectedPackages.put(arp.getKey().substring(PKG_PREFIX.length()), arp.isChecked());
+ }
+ return true;
+ }
+ return false;
+ }
+}
diff --git a/src/com/android/settings/users/RestrictionsReceiver.java b/src/com/android/settings/users/RestrictionsReceiver.java
new file mode 100644
index 0000000..0eeb7cd
--- /dev/null
+++ b/src/com/android/settings/users/RestrictionsReceiver.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2013 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.users;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.RestrictionEntry;
+import android.os.Bundle;
+import android.util.Log;
+
+import com.android.settings.R;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/** Test class, to demonstrate the features. TODO: Remove or modify with real restrictions */
+public class RestrictionsReceiver extends BroadcastReceiver {
+
+ private static final String TAG = RestrictionsReceiver.class.getSimpleName();
+
+ public static final String KEY_VERSION = "version";
+ public static final String KEY_ENABLE_APPS = "enable_apps";
+ public static final String KEY_SECTIONS_TO_SHOW = "enable_sections";
+ public static final String KEY_CONTENT_RATING = "content_rating";
+
+ private static final int[] SECTION_IDS = {
+ R.id.wifi_settings,
+ R.id.bluetooth_settings,
+ R.id.data_usage_settings,
+ R.id.app_settings,
+ R.id.date_time_settings,
+ R.id.about_settings
+ };
+
+ private static final int[] SECTION_TITLE_IDS = {
+ R.string.wifi_settings,
+ R.string.bluetooth_settings,
+ R.string.data_usage_summary_title,
+ R.string.manageapplications_settings_title,
+ R.string.date_and_time,
+ R.string.about_settings
+ };
+
+ @Override
+ public void onReceive(final Context context, Intent intent) {
+ final PendingResult result = goAsync();
+ final ArrayList<RestrictionEntry> oldRestrictions =
+ intent.getParcelableArrayListExtra(Intent.EXTRA_RESTRICTIONS);
+ Log.i(TAG, "oldRestrictions = " + oldRestrictions);
+ new Thread() {
+ public void run() {
+ createRestrictions(context, result, oldRestrictions);
+ }
+ }.start();
+ }
+
+ private void createRestrictions(Context context,
+ PendingResult result, List<RestrictionEntry> old) {
+ ArrayList<RestrictionEntry> newRestrictions = new ArrayList<RestrictionEntry>();
+ boolean oldEnableApps = false;
+ String oldContentRating = "";
+ String[] oldEnabledSections = new String[0];
+ if (old != null) {
+ for (RestrictionEntry r : old) {
+ if (r.key.equals(KEY_ENABLE_APPS)) {
+ oldEnableApps = r.getBooleanValue();
+ } else if (r.key.equals(KEY_CONTENT_RATING)) {
+ oldContentRating = r.getStringValue();
+ } else if (r.key.equals(KEY_SECTIONS_TO_SHOW)) {
+ oldEnabledSections = r.getMultipleValues();
+ }
+ }
+ }
+
+ RestrictionEntry r0 = new RestrictionEntry(KEY_VERSION, "1");
+ newRestrictions.add(r0);
+
+ RestrictionEntry r1 = new RestrictionEntry(KEY_ENABLE_APPS,
+ Boolean.toString(oldEnableApps));
+ r1.title = "Enable apps";
+ r1.description = "Show the Apps section in Settings";
+ r1.type = RestrictionEntry.TYPE_BOOLEAN;
+ newRestrictions.add(r1);
+
+ RestrictionEntry r2 = new RestrictionEntry(KEY_CONTENT_RATING, oldContentRating);
+ r2.title = "Test: Content rating";
+ r2.description = "Limit content to chosen rating and lower";
+ r2.type = RestrictionEntry.TYPE_CHOICE_LEVEL;
+ r2.values = new String[] { "G", "PG", "PG13", "R", "NR" };
+ r2.choices = new String[] { "G", "PG", "PG-13", "Restricted", "Not Rated" };
+ newRestrictions.add(r2);
+
+ String [] values = new String[SECTION_IDS.length];
+ String [] choices = new String[SECTION_IDS.length];
+ int i = 0;
+ for (int sectionId : SECTION_IDS) {
+ values[i] = Integer.toString(sectionId);
+ choices[i] = context.getString(SECTION_TITLE_IDS[i]);
+ i++;
+ }
+ RestrictionEntry r3 = new RestrictionEntry(KEY_SECTIONS_TO_SHOW, oldEnabledSections);
+ r3.type = RestrictionEntry.TYPE_MULTI_SELECT;
+ r3.choices = choices;
+ r3.values = values;
+ r3.title = "Test: Sections to show";
+ newRestrictions.add(r3);
+
+ Bundle extras = new Bundle();
+ extras.putParcelableArrayList(Intent.EXTRA_RESTRICTIONS, newRestrictions);
+ result.setResult(0, null, extras);
+ result.finish();
+ }
+}
diff --git a/src/com/android/settings/users/UserPreference.java b/src/com/android/settings/users/UserPreference.java
index 23cca73..6889747 100644
--- a/src/com/android/settings/users/UserPreference.java
+++ b/src/com/android/settings/users/UserPreference.java
@@ -20,6 +20,7 @@
import com.android.settings.R;
import android.content.Context;
+import android.os.UserHandle;
import android.os.UserManager;
import android.preference.Preference;
import android.util.AttributeSet;
@@ -31,21 +32,32 @@
public static final int USERID_UNKNOWN = -10;
private OnClickListener mDeleteClickListener;
+ private OnClickListener mSettingsClickListener;
private int mSerialNumber = -1;
private int mUserId = USERID_UNKNOWN;
+ private boolean mRestricted;
+ static final int SETTINGS_ID = R.id.manage_user;
+ static final int DELETE_ID = R.id.trash_user;
public UserPreference(Context context, AttributeSet attrs) {
- this(context, attrs, USERID_UNKNOWN, false, null);
+ this(context, attrs, USERID_UNKNOWN, false, null, null);
}
- UserPreference(Context context, AttributeSet attrs, int userId, boolean showDelete,
- OnClickListener deleteListener) {
+ UserPreference(Context context, AttributeSet attrs, int userId,
+ boolean showOptions, OnClickListener deleteListener,
+ OnClickListener settingsListener) {
super(context, attrs);
- if (showDelete) {
+ if (showOptions) {
setWidgetLayoutResource(R.layout.preference_user_delete_widget);
mDeleteClickListener = deleteListener;
+ mSettingsClickListener = settingsListener;
}
mUserId = userId;
+ if (mUserId > UserHandle.USER_OWNER) {
+ mRestricted = ((UserManager) getContext().getSystemService(Context.USER_SERVICE))
+ .getUserInfo(mUserId).isRestricted();
+ }
+ setSummary(mRestricted ? R.string.user_limited : R.string.user_trusted);
}
@Override
@@ -55,6 +67,15 @@
deleteView.setOnClickListener(mDeleteClickListener);
deleteView.setTag(this);
}
+ View settingsView = view.findViewById(R.id.manage_user);
+ if (settingsView != null) {
+ if (mRestricted) {
+ settingsView.setOnClickListener(mSettingsClickListener);
+ settingsView.setTag(this);
+ } else {
+ settingsView.setVisibility(View.INVISIBLE);
+ }
+ }
super.onBindView(view);
}
diff --git a/src/com/android/settings/users/UserRestrictionsActivity.java b/src/com/android/settings/users/UserRestrictionsActivity.java
new file mode 100644
index 0000000..5f377f3
--- /dev/null
+++ b/src/com/android/settings/users/UserRestrictionsActivity.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2013 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.users;
+
+import android.accounts.Account;
+import android.accounts.AccountManager;
+import android.app.Activity;
+import android.content.Context;
+import android.content.pm.IPackageManager;
+import android.content.pm.PackageManager;
+import android.content.pm.UserInfo;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.Button;
+
+import com.android.settings.R;
+
+import java.util.Map;
+
+public class UserRestrictionsActivity extends Activity implements OnClickListener {
+
+ private static final String TAG = UserRestrictionsActivity.class.getSimpleName();
+
+ static final String EXTRA_USER_NAME = "user_name";
+ static final String EXTRA_USER_ID = "user_id";
+ static final String EXTRA_ACCOUNTS = "accounts";
+
+ private Button mFinishButton;
+ private Button mBackButton;
+ private AppRestrictionsFragment mAppsFragment;
+ private UserInfo mUserInfo;
+ private boolean mNewUser;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ setContentView(R.layout.user_limits);
+
+ mBackButton = (Button) findViewById(R.id.back_button);
+ if (mBackButton != null) {
+ mBackButton.setOnClickListener(this);
+ }
+ mFinishButton = (Button) findViewById(R.id.next_button);
+ if (mFinishButton != null) {
+ mFinishButton.setOnClickListener(this);
+ }
+ mAppsFragment = (AppRestrictionsFragment)
+ getFragmentManager().findFragmentById(R.id.user_limits_fragment);
+
+ UserManager um = (UserManager) getSystemService(Context.USER_SERVICE);
+ String name = getIntent().getStringExtra(EXTRA_USER_NAME);
+ int userId = getIntent().getIntExtra(EXTRA_USER_ID, -1);
+ // Create the user so we have an id
+ if (userId == -1) {
+ mNewUser = true;
+ mUserInfo = um.createUser(name, UserInfo.FLAG_RESTRICTED);
+ um.setUserRestriction(UserManager.ALLOW_MODIFY_ACCOUNTS, false,
+ new UserHandle(mUserInfo.id));
+
+ Bitmap bitmap = BitmapFactory.decodeResource(getResources(),
+ UserSettings.USER_DRAWABLES[
+ mUserInfo.id % UserSettings.USER_DRAWABLES.length]);
+ um.setUserIcon(mUserInfo.id, bitmap);
+ } else {
+ mUserInfo = um.getUserInfo(userId);
+ }
+ if (mAppsFragment != null) {
+ mAppsFragment.setUser(new UserHandle(mUserInfo.id), mNewUser);
+ }
+ }
+
+ @Override
+ public void onClick(View v) {
+ if (v == mFinishButton) {
+ if (mNewUser) {
+ AccountManager am = AccountManager.get(this);
+ Account [] accounts = am.getAccounts();
+ if (accounts != null) {
+ for (Account account : accounts) {
+ am.addSharedAccount(account,
+ new UserHandle(mUserInfo.id));
+ }
+ }
+ }
+
+ IPackageManager ipm = IPackageManager.Stub.asInterface(
+ ServiceManager.getService("package"));
+ for (Map.Entry<String,Boolean> entry : mAppsFragment.mSelectedPackages.entrySet()) {
+ if (entry.getValue()) {
+ // Enable selected apps
+ try {
+ ipm.installExistingPackageAsUser(entry.getKey(), mUserInfo.id);
+ } catch (RemoteException re) {
+ }
+ } else {
+ // Blacklist all other apps, system or downloaded
+ try {
+ ipm.deletePackageAsUser(entry.getKey(), null, mUserInfo.id,
+ PackageManager.DELETE_SYSTEM_APP);
+ } catch (RemoteException re) {
+ }
+ }
+ }
+ setResult(RESULT_OK);
+ mUserInfo = null;
+ finish();
+ }
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+
+ if (mUserInfo != null && mNewUser) {
+ UserManager um = (UserManager) getSystemService(Context.USER_SERVICE);
+ um.removeUser(mUserInfo.id);
+ }
+ }
+}
diff --git a/src/com/android/settings/users/UserSettings.java b/src/com/android/settings/users/UserSettings.java
index dbaaf37..b6385c8 100644
--- a/src/com/android/settings/users/UserSettings.java
+++ b/src/com/android/settings/users/UserSettings.java
@@ -16,6 +16,8 @@
package com.android.settings.users;
+import android.accounts.Account;
+import android.accounts.AccountManager;
import android.app.ActivityManagerNative;
import android.app.AlertDialog;
import android.app.Dialog;
@@ -76,6 +78,8 @@
private static final String KEY_USER_NICKNAME = "user_nickname";
private static final String KEY_USER_LIST = "user_list";
private static final String KEY_USER_ME = "user_me";
+ private static final String KEY_ADD_RESTRICTED_USER = "user_add_restricted";
+ private static final String KEY_ADD_TRUSTED_USER = "user_add_trusted";
private static final int MENU_ADD_USER = Menu.FIRST;
private static final int MENU_REMOVE_USER = Menu.FIRST+1;
@@ -91,7 +95,7 @@
private static final String KEY_ADD_USER_LONG_MESSAGE_DISPLAYED =
"key_add_user_long_message_displayed";
- private static final int[] USER_DRAWABLES = {
+ static final int[] USER_DRAWABLES = {
R.drawable.avatar_default_1,
R.drawable.avatar_default_2,
R.drawable.avatar_default_3,
@@ -105,6 +109,8 @@
private PreferenceGroup mUserListCategory;
private Preference mMePreference;
private SelectableEditTextPreference mNicknamePreference;
+ private Preference mAddRestrictedUser;
+ private Preference mAddTrustedUser;
private int mRemovingUserId = -1;
private int mAddedUserId = 0;
private boolean mAddingUser;
@@ -176,6 +182,14 @@
InputType.TYPE_TEXT_VARIATION_NORMAL | InputType.TYPE_TEXT_FLAG_CAP_WORDS);
mNicknamePreference.setInitialSelectionMode(
SelectableEditTextPreference.SELECTION_SELECT_ALL);
+ mAddRestrictedUser = findPreference(KEY_ADD_RESTRICTED_USER);
+ mAddTrustedUser = findPreference(KEY_ADD_TRUSTED_USER);
+ mAddRestrictedUser.setOnPreferenceClickListener(this);
+ mAddTrustedUser.setOnPreferenceClickListener(this);
+ if (!mIsOwner || UserManager.getMaxSupportedUsers() < 2) {
+ removePreference(KEY_ADD_RESTRICTED_USER);
+ removePreference(KEY_ADD_TRUSTED_USER);
+ }
loadProfile();
setHasOptionsMenu(true);
IntentFilter filter = new IntentFilter(Intent.ACTION_USER_REMOVED);
@@ -207,13 +221,7 @@
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
- if (mIsOwner) {
- if (UserManager.getMaxSupportedUsers() > mUserManager.getUsers(false).size()) {
- MenuItem addUserItem = menu.add(0, MENU_ADD_USER, 0, R.string.user_add_user_menu);
- addUserItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM
- | MenuItem.SHOW_AS_ACTION_WITH_TEXT);
- }
- } else {
+ if (!mIsOwner) {
String nickname = mUserManager.getUserName();
MenuItem removeThisUser = menu.add(0, MENU_REMOVE_USER, 0,
getResources().getString(R.string.user_remove_user_menu, nickname));
@@ -284,6 +292,13 @@
}
}
+ private void onManageUserClicked(int userId) {
+ Intent appsChooser = new Intent();
+ appsChooser.setClass(getActivity(), UserRestrictionsActivity.class);
+ appsChooser.putExtra(UserRestrictionsActivity.EXTRA_USER_ID, userId);
+ startActivity(appsChooser);
+ }
+
private void onUserCreated(int userId) {
mAddedUserId = userId;
showDialog(DIALOG_SETUP_USER);
@@ -438,7 +453,7 @@
mNicknamePreference.setSummary(user.name);
} else {
pref = new UserPreference(getActivity(), null, user.id,
- UserHandle.myUserId() == UserHandle.USER_OWNER, this);
+ UserHandle.myUserId() == UserHandle.USER_OWNER, this, this);
pref.setOnPreferenceClickListener(this);
pref.setKey("id=" + user.id);
mUserListCategory.addPreference(pref);
@@ -446,9 +461,9 @@
pref.setSummary(R.string.user_owner);
}
pref.setTitle(user.name);
- if (!isInitialized(user)) {
- pref.setSummary(R.string.user_summary_not_set_up);
- }
+// if (!isInitialized(user)) {
+// pref.setSummary(R.string.user_summary_not_set_up);
+// }
}
if (user.iconPath != null) {
if (mUserIcons.get(user.id) == null) {
@@ -462,10 +477,10 @@
// Add a temporary entry for the user being created
if (mAddingUser) {
Preference pref = new UserPreference(getActivity(), null, UserPreference.USERID_UNKNOWN,
- false, null);
+ false, null, null);
pref.setEnabled(false);
pref.setTitle(R.string.user_new_user_name);
- pref.setSummary(R.string.user_adding_new_user);
+ //pref.setSummary(R.string.user_adding_new_user);
pref.setIcon(R.drawable.avatar_default_1);
mUserListCategory.addPreference(pref);
}
@@ -557,6 +572,17 @@
MESSAGE_SETUP_USER, user.id, user.serialNumber));
}
}
+ } else if (pref == mAddTrustedUser) {
+ onAddUserClicked();
+ } else if (pref == mAddRestrictedUser) {
+ Account[] accounts = ((AccountManager) getSystemService(Context.ACCOUNT_SERVICE))
+ .getAccounts();
+ Intent intent = new Intent(getActivity(), UserRestrictionsActivity.class);
+ intent.putExtra(UserRestrictionsActivity.EXTRA_USER_NAME,
+ getResources().getString(R.string.user_new_user_name));
+ intent.putExtra(UserRestrictionsActivity.EXTRA_ACCOUNTS,
+ accounts);
+ startActivity(intent);
}
return false;
}
@@ -569,7 +595,14 @@
public void onClick(View v) {
if (v.getTag() instanceof UserPreference) {
int userId = ((UserPreference) v.getTag()).getUserId();
- onRemoveUserClicked(userId);
+ switch (v.getId()) {
+ case UserPreference.DELETE_ID:
+ onRemoveUserClicked(userId);
+ break;
+ case UserPreference.SETTINGS_ID:
+ onManageUserClicked(userId);
+ break;
+ }
}
}