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
This commit is contained in:
Amith Yamasani
2013-03-01 17:05:23 -08:00
parent 9f5b49192d
commit 233592bb43
14 changed files with 1128 additions and 22 deletions

View File

@@ -69,6 +69,7 @@
android:taskAffinity="" android:taskAffinity=""
android:theme="@android:style/Theme.Holo" android:theme="@android:style/Theme.Holo"
android:hardwareAccelerated="true" android:hardwareAccelerated="true"
android:requiredForAllUsers="true"
android:supportsRtl="true"> android:supportsRtl="true">
<!-- Settings --> <!-- Settings -->
@@ -85,6 +86,16 @@
</intent-filter> </intent-filter>
</activity> </activity>
<!-- User Restrictions activity -->
<activity android:name=".users.UserRestrictionsActivity"
android:label="@string/user_restrictions_title">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<activity android:name=".SubSettings" <activity android:name=".SubSettings"
android:taskAffinity="com.android.settings" android:taskAffinity="com.android.settings"
android:parentActivityName="Settings"> android:parentActivityName="Settings">
@@ -734,6 +745,16 @@
</intent-filter> </intent-filter>
</activity-alias> </activity-alias>
<activity android:name=".users.AppRestrictionsFragment$Activity"
android:label="@string/application_info_label"
android:exported="true"
android:taskAffinity="">
<intent-filter>
<action android:name="com.android.settings.APP_RESTRICTIONS" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<!-- Provide direct entry into manage apps showing running services. --> <!-- Provide direct entry into manage apps showing running services. -->
<activity android:name="Settings$RunningServicesActivity" <activity android:name="Settings$RunningServicesActivity"
android:label="@string/runningservices_settings_title" android:label="@string/runningservices_settings_title"
@@ -1516,6 +1537,22 @@
android:resource="@id/display_settings" /> android:resource="@id/display_settings" />
</activity> </activity>
<activity android:name="Settings$UserSettingsActivity"
android:uiOptions="splitActionBarWhenNarrow"
android:label="@string/user_settings_title"
android:taskAffinity=""
android:excludeFromRecents="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<action android:name="android.settings.USER_SETTINGS" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
<meta-data android:name="com.android.settings.FRAGMENT_CLASS"
android:value="com.android.settings.users.UserSettings" />
<meta-data android:name="com.android.settings.TOP_LEVEL_HEADER_ID"
android:resource="@id/user_settings" />
</activity>
<receiver android:name=".widget.SettingsAppWidgetProvider" <receiver android:name=".widget.SettingsAppWidgetProvider"
android:label="@string/gadget_title" android:label="@string/gadget_title"
android:exported="true" android:exported="true"
@@ -1546,5 +1583,11 @@
</intent-filter> </intent-filter>
</receiver> </receiver>
<receiver android:name=".users.RestrictionsReceiver">
<intent-filter>
<action android:name="android.intent.action.GET_RESTRICTION_ENTRIES"/>
</intent-filter>
</receiver>
</application> </application>
</manifest> </manifest>

View File

@@ -0,0 +1,107 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?android:attr/listPreferredItemHeight"
android:gravity="center_vertical"
android:paddingStart="@*android:dimen/preference_item_padding_side"
android:paddingEnd="?android:attr/scrollbarSize">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:id="@+id/app_restrictions_pref"
android:focusable="true"
android:clickable="true"
android:gravity="center_vertical"
android:background="?android:attr/selectableItemBackground" >
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center"
android:minWidth="@*android:dimen/preference_icon_minWidth"
android:orientation="horizontal">
<ImageView
android:id="@+android:id/icon"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_gravity="center"
android:minWidth="48dp"
android:scaleType="centerInside"
android:layout_marginEnd="@*android:dimen/preference_item_padding_inner"
/>
</LinearLayout>
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="6dip"
android:layout_marginTop="6dip"
android:layout_marginBottom="6dip"
android:layout_weight="1">
<TextView
android:id="@+android:id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="true"
android:textAppearance="?android:attr/textAppearanceMedium"
android:ellipsize="marquee"
android:fadingEdge="horizontal"/>
<TextView
android:id="@android:id/summary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@android:id/title"
android:layout_alignStart="@android:id/title"
android:paddingBottom="3dip"
android:visibility="gone"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textSize="13sp"
android:textColor="?android:attr/textColorSecondary"
android:focusable="false"
android:maxLines="4" />
</RelativeLayout>
</LinearLayout>
<ImageView
android:id="@+id/app_restrictions_settings"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:paddingStart="12dip"
android:paddingEnd="12dp"
android:src="@drawable/ic_sysbar_quicksettings"
android:contentDescription="@string/apps_with_restrictions_settings_button"
android:layout_gravity="center"
android:clickable="true"
android:focusable="true"
android:background="?android:attr/selectableItemBackground" />
<View
android:id="@+id/settings_divider"
android:layout_width="1dip"
android:layout_height="match_parent"
android:layout_marginTop="5dip"
android:layout_marginBottom="5dip"
android:background="@android:drawable/divider_horizontal_dark" />
<LinearLayout
android:id="@android:id/widget_frame"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:paddingRight="?android:attr/scrollbarSize"
android:gravity="center_vertical"
android:orientation="vertical" />
</LinearLayout>

View File

@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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.
-->
<!-- Layout for a text label in the user limits screen. -->
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/user_rename" />

View File

@@ -20,6 +20,16 @@
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="match_parent" android:layout_height="match_parent"
android:orientation="horizontal"> android:orientation="horizontal">
<ImageView
android:id="@+id/manage_user"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:paddingStart="12dip"
android:paddingEnd="12dip"
android:src="@drawable/ic_sysbar_quicksettings"
android:contentDescription="@string/user_delete_user_description"
android:layout_gravity="center"
android:background="?android:attr/selectableItemBackground" />
<View <View
android:layout_width="2dip" android:layout_width="2dip"
android:layout_height="match_parent" android:layout_height="match_parent"
@@ -30,8 +40,8 @@
android:id="@+id/trash_user" android:id="@+id/trash_user"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="fill_parent" android:layout_height="fill_parent"
android:paddingStart="15dip" android:paddingStart="12dip"
android:paddingEnd="?android:attr/scrollbarSize" android:paddingEnd="12dip"
android:src="@drawable/ic_menu_delete_holo_dark" android:src="@drawable/ic_menu_delete_holo_dark"
android:contentDescription="@string/user_delete_user_description" android:contentDescription="@string/user_delete_user_description"
android:layout_gravity="center" android:layout_gravity="center"

View File

@@ -0,0 +1,55 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/*
** Copyright 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.
*/
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:layout_marginStart="32dp"
android:layout_marginEnd="32dp"
android:orientation="vertical">
<fragment android:name="com.android.settings.users.AppRestrictionsFragment"
android:id="@+id/user_limits_fragment"
android:layout_weight="1"
android:layout_width="match_parent"
android:layout_height="0dp"
/>
<RelativeLayout
android:id="@+id/button_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="0" >
<Button
android:id="@+id/back_button"
android:layout_width="150dip"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_margin="5dip"
android:text="@string/wizard_back"
android:visibility="invisible"/>
<Button
android:id="@+id/next_button"
android:layout_width="150dip"
android:layout_height="wrap_content"
android:layout_margin="5dip"
android:layout_alignParentEnd="true"
android:text="@string/wizard_finish" />
</RelativeLayout>
</LinearLayout>

View File

@@ -4273,12 +4273,25 @@
<string name="user_list_title">Other users</string> <string name="user_list_title">Other users</string>
<!-- User settings add user menu [CHAR LIMIT=20] --> <!-- User settings add user menu [CHAR LIMIT=20] -->
<string name="user_add_user_menu">Add user</string> <string name="user_add_user_menu">Add user</string>
<!-- User settings add restricted user label [CHAR LIMIT=20] -->
<string name="user_add_restricted">Add limited user</string>
<!-- User settings summary for add restricted user [CHAR LIMIT=100] -->
<string name="user_add_restricted_summary">Limited users can only access the apps and content you select</string>
<!-- User settings add user label [CHAR LIMIT=20] -->
<string name="user_add_trusted">Add trusted user</string>
<!-- User settings summary for add trusted user [CHAR LIMIT=100] -->
<string name="user_add_trusted_summary">Trusted users have no restrictions</string>
<!-- User summary to indicate that user is currently active in the background [CHAR LIMIT=100] --> <!-- User summary to indicate that user is currently active in the background [CHAR LIMIT=100] -->
<string name="user_summary_active">Active</string> <string name="user_summary_active">Active</string>
<!-- User summary to indicate that user is currently inactive in the background [CHAR LIMIT=100] --> <!-- User summary to indicate that user is currently inactive in the background [CHAR LIMIT=100] -->
<string name="user_summary_inactive">Not active</string> <string name="user_summary_inactive">Not active</string>
<!-- User summary to indicate that user is currently not set up [CHAR LIMIT=100] --> <!-- User summary to indicate that user is currently not set up [CHAR LIMIT=100] -->
<string name="user_summary_not_set_up">Not set up</string> <string name="user_summary_not_set_up">Not set up</string>
<!-- Summary text for a trusted user [CHAR LIMIT=50] -->
<string name="user_trusted">Trusted</string>
<!-- Summary text for a limited user [CHAR LIMIT=50] -->
<string name="user_limited">Limited</string>
<!-- User information string to represent the owner of the device [CHAR LIMIT=25] --> <!-- User information string to represent the owner of the device [CHAR LIMIT=25] -->
<string name="user_owner">Owner</string> <string name="user_owner">Owner</string>
<!-- Title for the preference to enter the nickname of the userto display in the user switcher [CHAR LIMIT=25]--> <!-- Title for the preference to enter the nickname of the userto display in the user switcher [CHAR LIMIT=25]-->
@@ -4325,6 +4338,13 @@
<!-- Delete button text [CHAR LIMIT=25] --> <!-- Delete button text [CHAR LIMIT=25] -->
<string name="user_delete_button">Delete</string> <string name="user_delete_button">Delete</string>
<!-- Application Restrictions screen title [CHAR LIMIT=45] -->
<string name="application_restrictions">Allow apps and content</string>
<!-- Applications with restrictions header [CHAR LIMIT=45] -->
<string name="apps_with_restrictions_header">Applications with restrictions</string>
<!-- Applicaitons with restrictions - settings button [CHAR LIMIT=30] -->
<string name="apps_with_restrictions_settings_button">Expand settings for application</string>
<!-- Warning message when changing a global setting for a tablet.[CHAR LIMIT=none] --> <!-- Warning message when changing a global setting for a tablet.[CHAR LIMIT=none] -->
<string name="global_change_warning" product="tablet">This setting affects all users on this tablet.</string> <string name="global_change_warning" product="tablet">This setting affects all users on this tablet.</string>
<!-- Warning message when changing a global setting for a phone.[CHAR LIMIT=none] --> <!-- Warning message when changing a global setting for a phone.[CHAR LIMIT=none] -->
@@ -4380,4 +4400,16 @@
<string name="cell_broadcast_settings">Cell broadcasts</string> <string name="cell_broadcast_settings">Cell broadcasts</string>
<!-- Cell Broadcast settings description [CHAR LIMIT=100] --> <!-- Cell Broadcast settings description [CHAR LIMIT=100] -->
<string name="cell_broadcast_settings_summary">Select the types of emergency alerts to display.</string> <string name="cell_broadcast_settings_summary">Select the types of emergency alerts to display.</string>
<!-- User app limits screen title [CHAR LIMIT=35] -->
<string name="user_restrictions_title">Allow apps and content</string>
<!-- User limits screen, user name rename text [CHAR LIMIT=15] -->
<string name="user_rename">RENAME</string>
<!-- Wizard back button label [CHAR LIMIT=25] -->
<string name="wizard_back">Back</string>
<!-- Wizard next button label [CHAR LIMIT=25] -->
<string name="wizard_next">Next</string>
<!-- Wizard next button label [CHAR LIMIT=25] -->
<string name="wizard_finish">Finish</string>
</resources> </resources>

View File

@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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.
-->
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
android:title="@string/application_restrictions"
xmlns:settings="http://schemas.android.com/apk/res/com.android.settings">
<EditTextPreference
android:key="user_info"
android:order="0"
android:widgetLayout="@layout/preference_rename_widget" />
</PreferenceScreen>

View File

@@ -39,4 +39,15 @@
android:title="@string/user_list_title"> android:title="@string/user_list_title">
</PreferenceCategory> </PreferenceCategory>
<Preference
android:key="user_add_restricted"
android:title="@string/user_add_restricted"
android:summary="@string/user_add_restricted_summary"
android:icon="@drawable/ic_menu_add" />
<Preference
android:key="user_add_trusted"
android:title="@string/user_add_trusted"
android:summary="@string/user_add_trusted_summary"
android:icon="@drawable/ic_menu_add" />
</PreferenceScreen> </PreferenceScreen>

View File

@@ -22,6 +22,7 @@ import android.accounts.OnAccountsUpdateListener;
import android.content.ComponentName; import android.content.ComponentName;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.RestrictionEntry;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.content.pm.ActivityInfo; import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
@@ -56,6 +57,7 @@ import com.android.settings.accounts.AuthenticatorHelper;
import com.android.settings.accounts.ManageAccountsSettings; import com.android.settings.accounts.ManageAccountsSettings;
import com.android.settings.bluetooth.BluetoothEnabler; import com.android.settings.bluetooth.BluetoothEnabler;
import com.android.settings.bluetooth.BluetoothSettings; import com.android.settings.bluetooth.BluetoothSettings;
import com.android.settings.users.RestrictionsReceiver;
import com.android.settings.wfd.WifiDisplaySettings; import com.android.settings.wfd.WifiDisplaySettings;
import com.android.settings.wifi.WifiEnabler; import com.android.settings.wifi.WifiEnabler;
import com.android.settings.wifi.WifiSettings; import com.android.settings.wifi.WifiSettings;
@@ -133,12 +135,16 @@ public class Settings extends PreferenceActivity
private Header mLastHeader; private Header mLastHeader;
private boolean mListeningToAccountUpdates; private boolean mListeningToAccountUpdates;
private List<RestrictionEntry> mAppRestrictions;
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
if (getIntent().hasExtra(EXTRA_UI_OPTIONS)) { if (getIntent().hasExtra(EXTRA_UI_OPTIONS)) {
getWindow().setUiOptions(getIntent().getIntExtra(EXTRA_UI_OPTIONS, 0)); getWindow().setUiOptions(getIntent().getIntExtra(EXTRA_UI_OPTIONS, 0));
} }
mAppRestrictions = getApplicationRestrictions();
mAuthenticatorHelper = new AuthenticatorHelper(); mAuthenticatorHelper = new AuthenticatorHelper();
mAuthenticatorHelper.updateAuthDescriptions(this); mAuthenticatorHelper.updateAuthDescriptions(this);
mAuthenticatorHelper.onAccountsUpdated(this, null); mAuthenticatorHelper.onAccountsUpdated(this, null);
@@ -408,7 +414,6 @@ public class Settings extends PreferenceActivity
DevelopmentSettings.PREF_SHOW, DevelopmentSettings.PREF_SHOW,
android.os.Build.TYPE.equals("eng")); android.os.Build.TYPE.equals("eng"));
int i = 0; int i = 0;
mHeaderIndexMap.clear(); mHeaderIndexMap.clear();
while (i < target.size()) { while (i < target.size()) {
Header header = target.get(i); Header header = target.get(i);
@@ -450,6 +455,15 @@ public class Settings extends PreferenceActivity
if (!showDev) { if (!showDev) {
target.remove(i); 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 if (i < target.size() && target.get(i) == header
@@ -828,4 +842,5 @@ public class Settings extends PreferenceActivity
public static class WifiDisplaySettingsActivity extends Settings { /* empty */ } public static class WifiDisplaySettingsActivity extends Settings { /* empty */ }
public static class DreamSettingsActivity extends Settings { /* empty */ } public static class DreamSettingsActivity extends Settings { /* empty */ }
public static class NotificationStationActivity extends Settings { /* empty */ } public static class NotificationStationActivity extends Settings { /* empty */ }
public static class UserSettingsActivity extends Settings { /* empty */ }
} }

View File

@@ -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;
}
}

View File

@@ -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();
}
}

View File

@@ -20,6 +20,7 @@ import com.android.internal.util.CharSequences;
import com.android.settings.R; import com.android.settings.R;
import android.content.Context; import android.content.Context;
import android.os.UserHandle;
import android.os.UserManager; import android.os.UserManager;
import android.preference.Preference; import android.preference.Preference;
import android.util.AttributeSet; import android.util.AttributeSet;
@@ -31,21 +32,32 @@ public class UserPreference extends Preference {
public static final int USERID_UNKNOWN = -10; public static final int USERID_UNKNOWN = -10;
private OnClickListener mDeleteClickListener; private OnClickListener mDeleteClickListener;
private OnClickListener mSettingsClickListener;
private int mSerialNumber = -1; private int mSerialNumber = -1;
private int mUserId = USERID_UNKNOWN; 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) { 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, UserPreference(Context context, AttributeSet attrs, int userId,
OnClickListener deleteListener) { boolean showOptions, OnClickListener deleteListener,
OnClickListener settingsListener) {
super(context, attrs); super(context, attrs);
if (showDelete) { if (showOptions) {
setWidgetLayoutResource(R.layout.preference_user_delete_widget); setWidgetLayoutResource(R.layout.preference_user_delete_widget);
mDeleteClickListener = deleteListener; mDeleteClickListener = deleteListener;
mSettingsClickListener = settingsListener;
} }
mUserId = userId; 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 @Override
@@ -55,6 +67,15 @@ public class UserPreference extends Preference {
deleteView.setOnClickListener(mDeleteClickListener); deleteView.setOnClickListener(mDeleteClickListener);
deleteView.setTag(this); 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); super.onBindView(view);
} }

View File

@@ -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);
}
}
}

View File

@@ -16,6 +16,8 @@
package com.android.settings.users; package com.android.settings.users;
import android.accounts.Account;
import android.accounts.AccountManager;
import android.app.ActivityManagerNative; import android.app.ActivityManagerNative;
import android.app.AlertDialog; import android.app.AlertDialog;
import android.app.Dialog; import android.app.Dialog;
@@ -76,6 +78,8 @@ public class UserSettings extends SettingsPreferenceFragment
private static final String KEY_USER_NICKNAME = "user_nickname"; private static final String KEY_USER_NICKNAME = "user_nickname";
private static final String KEY_USER_LIST = "user_list"; private static final String KEY_USER_LIST = "user_list";
private static final String KEY_USER_ME = "user_me"; 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_ADD_USER = Menu.FIRST;
private static final int MENU_REMOVE_USER = Menu.FIRST+1; private static final int MENU_REMOVE_USER = Menu.FIRST+1;
@@ -91,7 +95,7 @@ public class UserSettings extends SettingsPreferenceFragment
private static final String KEY_ADD_USER_LONG_MESSAGE_DISPLAYED = private static final String KEY_ADD_USER_LONG_MESSAGE_DISPLAYED =
"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_1,
R.drawable.avatar_default_2, R.drawable.avatar_default_2,
R.drawable.avatar_default_3, R.drawable.avatar_default_3,
@@ -105,6 +109,8 @@ public class UserSettings extends SettingsPreferenceFragment
private PreferenceGroup mUserListCategory; private PreferenceGroup mUserListCategory;
private Preference mMePreference; private Preference mMePreference;
private SelectableEditTextPreference mNicknamePreference; private SelectableEditTextPreference mNicknamePreference;
private Preference mAddRestrictedUser;
private Preference mAddTrustedUser;
private int mRemovingUserId = -1; private int mRemovingUserId = -1;
private int mAddedUserId = 0; private int mAddedUserId = 0;
private boolean mAddingUser; private boolean mAddingUser;
@@ -176,6 +182,14 @@ public class UserSettings extends SettingsPreferenceFragment
InputType.TYPE_TEXT_VARIATION_NORMAL | InputType.TYPE_TEXT_FLAG_CAP_WORDS); InputType.TYPE_TEXT_VARIATION_NORMAL | InputType.TYPE_TEXT_FLAG_CAP_WORDS);
mNicknamePreference.setInitialSelectionMode( mNicknamePreference.setInitialSelectionMode(
SelectableEditTextPreference.SELECTION_SELECT_ALL); 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(); loadProfile();
setHasOptionsMenu(true); setHasOptionsMenu(true);
IntentFilter filter = new IntentFilter(Intent.ACTION_USER_REMOVED); IntentFilter filter = new IntentFilter(Intent.ACTION_USER_REMOVED);
@@ -207,13 +221,7 @@ public class UserSettings extends SettingsPreferenceFragment
@Override @Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
if (mIsOwner) { 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 {
String nickname = mUserManager.getUserName(); String nickname = mUserManager.getUserName();
MenuItem removeThisUser = menu.add(0, MENU_REMOVE_USER, 0, MenuItem removeThisUser = menu.add(0, MENU_REMOVE_USER, 0,
getResources().getString(R.string.user_remove_user_menu, nickname)); getResources().getString(R.string.user_remove_user_menu, nickname));
@@ -284,6 +292,13 @@ public class UserSettings extends SettingsPreferenceFragment
} }
} }
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) { private void onUserCreated(int userId) {
mAddedUserId = userId; mAddedUserId = userId;
showDialog(DIALOG_SETUP_USER); showDialog(DIALOG_SETUP_USER);
@@ -438,7 +453,7 @@ public class UserSettings extends SettingsPreferenceFragment
mNicknamePreference.setSummary(user.name); mNicknamePreference.setSummary(user.name);
} else { } else {
pref = new UserPreference(getActivity(), null, user.id, pref = new UserPreference(getActivity(), null, user.id,
UserHandle.myUserId() == UserHandle.USER_OWNER, this); UserHandle.myUserId() == UserHandle.USER_OWNER, this, this);
pref.setOnPreferenceClickListener(this); pref.setOnPreferenceClickListener(this);
pref.setKey("id=" + user.id); pref.setKey("id=" + user.id);
mUserListCategory.addPreference(pref); mUserListCategory.addPreference(pref);
@@ -446,9 +461,9 @@ public class UserSettings extends SettingsPreferenceFragment
pref.setSummary(R.string.user_owner); pref.setSummary(R.string.user_owner);
} }
pref.setTitle(user.name); pref.setTitle(user.name);
if (!isInitialized(user)) { // if (!isInitialized(user)) {
pref.setSummary(R.string.user_summary_not_set_up); // pref.setSummary(R.string.user_summary_not_set_up);
} // }
} }
if (user.iconPath != null) { if (user.iconPath != null) {
if (mUserIcons.get(user.id) == null) { if (mUserIcons.get(user.id) == null) {
@@ -462,10 +477,10 @@ public class UserSettings extends SettingsPreferenceFragment
// Add a temporary entry for the user being created // Add a temporary entry for the user being created
if (mAddingUser) { if (mAddingUser) {
Preference pref = new UserPreference(getActivity(), null, UserPreference.USERID_UNKNOWN, Preference pref = new UserPreference(getActivity(), null, UserPreference.USERID_UNKNOWN,
false, null); false, null, null);
pref.setEnabled(false); pref.setEnabled(false);
pref.setTitle(R.string.user_new_user_name); 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); pref.setIcon(R.drawable.avatar_default_1);
mUserListCategory.addPreference(pref); mUserListCategory.addPreference(pref);
} }
@@ -557,6 +572,17 @@ public class UserSettings extends SettingsPreferenceFragment
MESSAGE_SETUP_USER, user.id, user.serialNumber)); 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; return false;
} }
@@ -569,7 +595,14 @@ public class UserSettings extends SettingsPreferenceFragment
public void onClick(View v) { public void onClick(View v) {
if (v.getTag() instanceof UserPreference) { if (v.getTag() instanceof UserPreference) {
int userId = ((UserPreference) v.getTag()).getUserId(); 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;
}
} }
} }