diff options
author | Fred Chung <fchung@google.com> | 2013-07-22 18:25:53 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2013-07-22 18:25:54 +0000 |
commit | 63bc4aaf4cef9e82fd6554f6a06f64815b809c6e (patch) | |
tree | 67d93f0266b4220250ffc0f566b3a97dc5dc9ad5 | |
parent | c821270d716ca73a998ece17c9d5bf593bdf590e (diff) | |
parent | b71371d3afe04a9c79f38ddea4ab02664c9b908d (diff) | |
download | android_development-63bc4aaf4cef9e82fd6554f6a06f64815b809c6e.tar.gz android_development-63bc4aaf4cef9e82fd6554f6a06f64815b809c6e.tar.bz2 android_development-63bc4aaf4cef9e82fd6554f6a06f64815b809c6e.zip |
Merge "App restriction for restricted profile sample." into jb-mr2-dev
15 files changed, 582 insertions, 207 deletions
diff --git a/build/sdk.atree b/build/sdk.atree index 6cb6967a3..59dc6fdf3 100644 --- a/build/sdk.atree +++ b/build/sdk.atree @@ -179,6 +179,7 @@ development/samples/ActionBarCompat samples/${PLATFORM_NAME}/ActionBa development/samples/AndroidBeamDemo samples/${PLATFORM_NAME}/AndroidBeamDemo development/samples/ApiDemos samples/${PLATFORM_NAME}/ApiDemos development/samples/AppNavigation samples/${PLATFORM_NAME}/AppNavigation +development/samples/AppRestrictions samples/${PLATFORM_NAME}/AppRestrictions development/samples/BackupRestore samples/${PLATFORM_NAME}/BackupRestore development/samples/BasicGLSurfaceView samples/${PLATFORM_NAME}/BasicGLSurfaceView development/samples/BluetoothChat samples/${PLATFORM_NAME}/BluetoothChat diff --git a/samples/AppLimits/src/com/example/android/applimits/CustomRestrictionsActivity.java b/samples/AppLimits/src/com/example/android/applimits/CustomRestrictionsActivity.java deleted file mode 100644 index 963aa2171..000000000 --- a/samples/AppLimits/src/com/example/android/applimits/CustomRestrictionsActivity.java +++ /dev/null @@ -1,159 +0,0 @@ -/* - * 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.example.android.applimits; - -import android.content.Context; -import android.content.Intent; -import android.content.RestrictionEntry; -import android.os.Bundle; -import android.os.UserManager; -import android.preference.CheckBoxPreference; -import android.preference.ListPreference; -import android.preference.MultiSelectListPreference; -import android.preference.Preference; -import android.preference.Preference.OnPreferenceChangeListener; -import android.preference.PreferenceActivity; - -import com.example.android.applimits.GetRestrictionsReceiver; - -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -public class CustomRestrictionsActivity extends PreferenceActivity - implements OnPreferenceChangeListener { - - private static final String KEY_CUSTOM_PREF = "custom"; - private static final String KEY_CHOICE_PREF = "choice"; - private static final String KEY_MULTI_PREF = "multi"; - - List<RestrictionEntry> mRestrictions; - private Bundle mRestrictionsBundle; - - CheckBoxPreference mCustomPref; - ListPreference mChoicePref; - MultiSelectListPreference mMultiPref; - - RestrictionEntry mCustomEntry; - RestrictionEntry mChoiceEntry; - RestrictionEntry mMultiEntry; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - mRestrictionsBundle = getIntent().getBundleExtra(Intent.EXTRA_RESTRICTIONS_BUNDLE); - if (mRestrictionsBundle == null) { - mRestrictionsBundle = - ((UserManager) getSystemService(Context.USER_SERVICE)) - .getApplicationRestrictions(getPackageName()); - } - if (mRestrictionsBundle == null) { - mRestrictionsBundle = new Bundle(); - } - - if (savedInstanceState != null - && savedInstanceState.containsKey(Intent.EXTRA_RESTRICTIONS_LIST)) { - mRestrictions = savedInstanceState.getParcelableArrayList( - Intent.EXTRA_RESTRICTIONS_LIST); - } - - this.addPreferencesFromResource(R.xml.custom_prefs); - mCustomPref = (CheckBoxPreference) findPreference(KEY_CUSTOM_PREF); - mChoicePref = (ListPreference) findPreference(KEY_CHOICE_PREF); - mMultiPref = (MultiSelectListPreference) findPreference(KEY_MULTI_PREF); - - // Transfer the saved values into the preference hierarchy - if (mRestrictions != null) { - for (RestrictionEntry entry : mRestrictions) { - if (entry.getKey().equals(GetRestrictionsReceiver.KEY_CUSTOM)) { - mCustomPref.setChecked(entry.getSelectedState()); - mCustomEntry = entry; - } else if (entry.getKey().equals(GetRestrictionsReceiver.KEY_CHOICE)) { - mChoicePref.setValue(entry.getSelectedString()); - mChoiceEntry = entry; - } else if (entry.getKey().equals(GetRestrictionsReceiver.KEY_MULTI_SELECT)) { - HashSet<String> set = new HashSet<String>(); - for (String value : entry.getAllSelectedStrings()) { - set.add(value); - } - mMultiPref.setValues(set); - mMultiEntry = entry; - } - } - } else { - mRestrictions = new ArrayList<RestrictionEntry>(); - mCustomEntry = new RestrictionEntry(GetRestrictionsReceiver.KEY_CUSTOM, - mRestrictionsBundle.getBoolean(GetRestrictionsReceiver.KEY_CUSTOM, false)); - mCustomEntry.setType(RestrictionEntry.TYPE_BOOLEAN); - mCustomPref.setChecked(mCustomEntry.getSelectedState()); - mChoiceEntry = new RestrictionEntry(GetRestrictionsReceiver.KEY_CHOICE, - mRestrictionsBundle.getString(GetRestrictionsReceiver.KEY_CHOICE)); - mChoiceEntry.setType(RestrictionEntry.TYPE_CHOICE); - mChoicePref.setValue(mChoiceEntry.getSelectedString()); - mMultiEntry = new RestrictionEntry(GetRestrictionsReceiver.KEY_MULTI_SELECT, - mRestrictionsBundle.getStringArray(GetRestrictionsReceiver.KEY_MULTI_SELECT)); - mMultiEntry.setType(RestrictionEntry.TYPE_MULTI_SELECT); - if (mMultiEntry.getAllSelectedStrings() != null) { - HashSet<String> set = new HashSet<String>(); - for (String value : mRestrictionsBundle.getStringArray( - GetRestrictionsReceiver.KEY_MULTI_SELECT)) { - set.add(value); - } - mMultiPref.setValues(set); - } - mRestrictions.add(mCustomEntry); - mRestrictions.add(mChoiceEntry); - mRestrictions.add(mMultiEntry); - } - mCustomPref.setOnPreferenceChangeListener(this); - mChoicePref.setOnPreferenceChangeListener(this); - mMultiPref.setOnPreferenceChangeListener(this); - Intent intent = new Intent(getIntent()); - intent.putParcelableArrayListExtra(Intent.EXTRA_RESTRICTIONS_LIST, - new ArrayList<RestrictionEntry>(mRestrictions)); - setResult(RESULT_OK, intent); - } - - public void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - outState.putParcelableArrayList(Intent.EXTRA_RESTRICTIONS_LIST, - new ArrayList<RestrictionEntry>(mRestrictions)); - } - - @Override - public boolean onPreferenceChange(Preference preference, Object newValue) { - if (preference == mCustomPref) { - mCustomEntry.setSelectedState((Boolean) newValue); - } else if (preference == mChoicePref) { - mChoiceEntry.setSelectedString((String) newValue); - } else if (preference == mMultiPref) { - String[] selectedStrings = new String[((Set<String>)newValue).size()]; - int i = 0; - for (String value : (Set<String>) newValue) { - selectedStrings[i++] = value; - } - mMultiEntry.setAllSelectedStrings(selectedStrings); - } - Intent intent = new Intent(getIntent()); - intent.putParcelableArrayListExtra(Intent.EXTRA_RESTRICTIONS_LIST, - new ArrayList<RestrictionEntry>(mRestrictions)); - setResult(RESULT_OK, intent); - return true; - } -} diff --git a/samples/AppLimits/Android.mk b/samples/AppRestrictions/Android.mk index 27252761a..6ab20da63 100644 --- a/samples/AppLimits/Android.mk +++ b/samples/AppRestrictions/Android.mk @@ -5,7 +5,7 @@ LOCAL_MODULE_TAGS := samples tests LOCAL_SRC_FILES := $(call all-java-files-under, src) -LOCAL_PACKAGE_NAME := AppLimits +LOCAL_PACKAGE_NAME := AppRestrictions LOCAL_SDK_VERSION := current diff --git a/samples/AppLimits/AndroidManifest.xml b/samples/AppRestrictions/AndroidManifest.xml index 8133fe9b3..7678a4585 100644 --- a/samples/AppLimits/AndroidManifest.xml +++ b/samples/AppRestrictions/AndroidManifest.xml @@ -14,29 +14,31 @@ limitations under the License. --> -<manifest android:versionCode="1" - android:versionName="1" - xmlns:android="http://schemas.android.com/apk/res/android" - package="com.example.android.applimits"> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + android:versionCode="1" + android:versionName="1" + package="com.example.android.apprestrictions"> + + <uses-sdk android:minSdkVersion="18" /> <application android:label="@string/app_name" - android:requiredForAllUsers="true"> + android:icon="@drawable/ic_launcher"> <activity android:name="CustomRestrictionsActivity" - android:exported="true" - android:label="@string/restrictions_activity_label"> + android:label="@string/restrictions_activity_label" /> + <activity android:name="MainActivity" + android:icon="@drawable/ic_launcher" + android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> - <receiver android:name="GetRestrictionsReceiver" - android:exported="true"> + <receiver android:name="GetRestrictionsReceiver"> <intent-filter> <action android:name="android.intent.action.GET_RESTRICTION_ENTRIES" /> </intent-filter> </receiver> - </application> </manifest> diff --git a/samples/AppRestrictions/res/drawable-hdpi/ic_launcher.png b/samples/AppRestrictions/res/drawable-hdpi/ic_launcher.png Binary files differnew file mode 100755 index 000000000..f36c473a1 --- /dev/null +++ b/samples/AppRestrictions/res/drawable-hdpi/ic_launcher.png diff --git a/samples/AppRestrictions/res/drawable-mdpi/ic_launcher.png b/samples/AppRestrictions/res/drawable-mdpi/ic_launcher.png Binary files differnew file mode 100755 index 000000000..5ab2e0d33 --- /dev/null +++ b/samples/AppRestrictions/res/drawable-mdpi/ic_launcher.png diff --git a/samples/AppRestrictions/res/drawable-xhdpi/ic_launcher.png b/samples/AppRestrictions/res/drawable-xhdpi/ic_launcher.png Binary files differnew file mode 100755 index 000000000..76228388e --- /dev/null +++ b/samples/AppRestrictions/res/drawable-xhdpi/ic_launcher.png diff --git a/samples/AppRestrictions/res/drawable-xxhdpi/ic_launcher.png b/samples/AppRestrictions/res/drawable-xxhdpi/ic_launcher.png Binary files differnew file mode 100755 index 000000000..7f55feff2 --- /dev/null +++ b/samples/AppRestrictions/res/drawable-xxhdpi/ic_launcher.png diff --git a/samples/AppRestrictions/res/layout/main.xml b/samples/AppRestrictions/res/layout/main.xml new file mode 100644 index 000000000..55e2c8eb4 --- /dev/null +++ b/samples/AppRestrictions/res/layout/main.xml @@ -0,0 +1,114 @@ +<?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. +--> +<ScrollView xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent"> + <LinearLayout android:orientation="vertical" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:layout_margin="20dp"> + + <TextView android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginBottom="10dp" + android:textSize="18sp" + android:text="@string/sample_app_description"/> + + <LinearLayout android:orientation="horizontal" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginBottom="15dp"> + <CheckBox android:id="@+id/custom_app_limits" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:onClick="onCustomClicked"/> + <TextView android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textSize="18sp" + android:text="@string/custom_description" + android:onClick="onCustomClicked" + android:layout_weight="1"/> + </LinearLayout> + + <!-- Separator --> + <View android:layout_height="1dp" + android:background="@android:color/white" + android:layout_width="match_parent" + android:layout_margin="25dp"/> + + <!-- Section to show app restriction settings under a restricted profile. --> + <TextView android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textSize="20sp" + android:text="@string/current_app_limits_label"/> + <TextView android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textSize="18sp" + android:layout_marginBottom="10dp" + android:text="@string/current_app_limits_description"/> + + <LinearLayout android:orientation="horizontal" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginLeft="20dp"> + <TextView android:layout_width="210dp" + android:layout_height="wrap_content" + android:textSize="18sp" + android:text="@string/boolean_entry_title"/> + <Space android:layout_height="1dp" + android:layout_width="15dp"/> + <TextView android:id="@+id/boolean_entry_id" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textSize="18sp" + android:text="@string/boolean_entry_title"/> + </LinearLayout> + + <LinearLayout android:orientation="horizontal" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginLeft="20dp"> + <TextView android:layout_width="210dp" + android:layout_height="wrap_content" + android:textSize="18sp" + android:text="@string/choice_entry_title"/> + <Space android:layout_height="1dp" + android:layout_width="15dp"/> + <TextView android:id="@+id/choice_entry_id" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textSize="18sp" + android:text="@string/boolean_entry_title"/> + </LinearLayout> + + <LinearLayout android:orientation="horizontal" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginLeft="20dp"> + <TextView android:layout_width="210dp" + android:layout_height="wrap_content" + android:textSize="18sp" + android:text="@string/multi_entry_title"/> + <Space android:layout_height="1dp" + android:layout_width="15dp"/> + <TextView android:id="@+id/multi_entry_id" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textSize="18sp" + android:text="@string/multi_entry_title"/> + </LinearLayout> + </LinearLayout> +</ScrollView>
\ No newline at end of file diff --git a/samples/AppLimits/res/values/strings.xml b/samples/AppRestrictions/res/values/strings.xml index d5b7721ba..2dac3b1bf 100644 --- a/samples/AppLimits/res/values/strings.xml +++ b/samples/AppRestrictions/res/values/strings.xml @@ -14,12 +14,29 @@ limitations under the License. --> <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="app_name">AppLimits Demo</string> + <string name="app_name">App Restrictions Demo</string> <string name="restrictions_activity_label">Custom app restrictions</string> - <string name="app_limits_main_label">App Limits</string> - <string name="custom_or_not_title">Test Custom Restrictions</string> + <string name="boolean_entry_title">Test boolean type</string> <string name="choice_entry_title">Test choice type</string> <string name="multi_entry_title">Test multi-select type</string> + <string name="custom_description">If checked, use a custom app restriction Activity. Otherwise, + use standard restriction types. + </string> + <string name="sample_app_description">Note: This sample app requires the restricted profile + feature.\n\n + 1. If this is the primary user, go to Settings > Users.\n\n + 2. Create a restricted profile, if one doesn\'t exist already.\n\n + 3. Open the profile settings, locate the sample app, and tap the app restriction settings + icon. Configure app restrictions for the app.\n\n + 4. In the lock screen, switch to the user\'s restricted profile, launch this sample app, + and see the configured app restrictions displayed.\n + </string> + <string name="settings_button_label">Go to Settings</string> + <string name="current_app_limits_label">Current app restriction settings:</string> + <string name="na">N/A</string> + <string name="current_app_limits_description">Your app can restrict its content based on these + settings, which can be configured through the primary user\'s Users Settings. + </string> <string-array name="multi_entry_entries"> <item>Ice Cream</item> diff --git a/samples/AppLimits/res/xml/custom_prefs.xml b/samples/AppRestrictions/res/xml/custom_prefs.xml index 2b4512582..5a3cf0df5 100644 --- a/samples/AppLimits/res/xml/custom_prefs.xml +++ b/samples/AppRestrictions/res/xml/custom_prefs.xml @@ -17,15 +17,15 @@ <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" android:title="@string/restrictions_activity_label"> - <CheckBoxPreference android:key="custom" - android:title="@string/custom_or_not_title" /> + <CheckBoxPreference android:key="pref_boolean" + android:title="@string/boolean_entry_title" /> - <ListPreference android:key="choice" + <ListPreference android:key="pref_choice" android:title="@string/choice_entry_title" android:entries="@array/choice_entry_entries" android:entryValues="@array/choice_entry_values" /> - <MultiSelectListPreference android:key="multi" + <MultiSelectListPreference android:key="pref_multi" android:title="@string/multi_entry_title" android:entries="@array/multi_entry_entries" android:entryValues="@array/multi_entry_values" /> diff --git a/samples/AppRestrictions/src/com/example/android/apprestrictions/CustomRestrictionsActivity.java b/samples/AppRestrictions/src/com/example/android/apprestrictions/CustomRestrictionsActivity.java new file mode 100644 index 000000000..213b31357 --- /dev/null +++ b/samples/AppRestrictions/src/com/example/android/apprestrictions/CustomRestrictionsActivity.java @@ -0,0 +1,44 @@ +/* + * 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.example.android.apprestrictions; + +import android.app.Activity; +import android.os.Bundle; + +/** + * This activity demonstrates how an app can integrate its own custom app restriction settings + * with the restricted profile feature. + * + * This sample app maintains custom app restriction settings in shared preferences. When + * the activity is invoked (from Settings > Users), the stored settings are used to initialize + * the custom configuration on the user interface. Three sample input types are + * shown: checkbox, single-choice, and multi-choice. When the settings are modified by the user, + * the corresponding restriction entries are saved, which are retrievable under a restricted + * profile. + */ +public class CustomRestrictionsActivity extends Activity { + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + if (savedInstanceState == null) { + getFragmentManager().beginTransaction().replace(android.R.id.content, + new CustomRestrictionsFragment()).commit(); + } + } +} diff --git a/samples/AppRestrictions/src/com/example/android/apprestrictions/CustomRestrictionsFragment.java b/samples/AppRestrictions/src/com/example/android/apprestrictions/CustomRestrictionsFragment.java new file mode 100644 index 000000000..b04dfd1f7 --- /dev/null +++ b/samples/AppRestrictions/src/com/example/android/apprestrictions/CustomRestrictionsFragment.java @@ -0,0 +1,202 @@ +/* + * 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.example.android.apprestrictions; + +import android.app.Activity; +import android.content.Context; +import android.content.Intent; +import android.content.RestrictionEntry; +import android.os.Bundle; +import android.os.UserManager; +import android.preference.CheckBoxPreference; +import android.preference.ListPreference; +import android.preference.MultiSelectListPreference; +import android.preference.Preference; +import android.preference.PreferenceFragment; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * This fragment is included in {@code CustomRestrictionsActivity}. It demonstrates how an app + * can integrate its own custom app restriction settings with the restricted profile feature. + * + * This sample app maintains custom app restriction settings in shared preferences. Your app + * can use other methods to maintain the settings. When this activity is invoked + * (from Settings > Users > Restricted Profile), the shared preferences are used to initialize + * the custom configuration on the user interface. + * + * Three sample input types are shown: checkbox, single-choice, and multi-choice. When the + * settings are modified by the user, the corresponding restriction entries are saved in the + * platform. The saved restriction entries are retrievable when the app is launched under a + * restricted profile. + */ +public class CustomRestrictionsFragment extends PreferenceFragment + implements Preference.OnPreferenceChangeListener { + + // Shared preference key for the boolean restriction. + private static final String KEY_BOOLEAN_PREF = "pref_boolean"; + // Shared preference key for the single-select restriction. + private static final String KEY_CHOICE_PREF = "pref_choice"; + // Shared preference key for the multi-select restriction. + private static final String KEY_MULTI_PREF = "pref_multi"; + + + private List<RestrictionEntry> mRestrictions; + private Bundle mRestrictionsBundle; + + // Shared preferences for each of the sample input types. + private CheckBoxPreference mBooleanPref; + private ListPreference mChoicePref; + private MultiSelectListPreference mMultiPref; + + // Restriction entries for each of the sample input types. + private RestrictionEntry mBooleanEntry; + private RestrictionEntry mChoiceEntry; + private RestrictionEntry mMultiEntry; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + addPreferencesFromResource(R.xml.custom_prefs); + + // This sample app uses shared preferences to maintain app restriction settings. Your app + // can use other methods to maintain the settings. + mBooleanPref = (CheckBoxPreference) findPreference(KEY_BOOLEAN_PREF); + mChoicePref = (ListPreference) findPreference(KEY_CHOICE_PREF); + mMultiPref = (MultiSelectListPreference) findPreference(KEY_MULTI_PREF); + + mBooleanPref.setOnPreferenceChangeListener(this); + mChoicePref.setOnPreferenceChangeListener(this); + mMultiPref.setOnPreferenceChangeListener(this); + + setRetainInstance(true); + } + + @Override + public void onActivityCreated(Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + final Activity activity = getActivity(); + + // BEGIN_INCLUDE (GET_CURRENT_RESTRICTIONS) + // Existing app restriction settings, if exist, can be retrieved from the Bundle. + mRestrictionsBundle = + activity.getIntent().getBundleExtra(Intent.EXTRA_RESTRICTIONS_BUNDLE); + + if (mRestrictionsBundle == null) { + mRestrictionsBundle = + ((UserManager) activity.getSystemService(Context.USER_SERVICE)) + .getApplicationRestrictions(activity.getPackageName()); + } + + if (mRestrictionsBundle == null) { + mRestrictionsBundle = new Bundle(); + } + + mRestrictions = activity.getIntent().getParcelableArrayListExtra( + Intent.EXTRA_RESTRICTIONS_LIST); + // END_INCLUDE (GET_CURRENT_RESTRICTIONS) + + // Transfers the saved values into the preference hierarchy. + if (mRestrictions != null) { + for (RestrictionEntry entry : mRestrictions) { + if (entry.getKey().equals(GetRestrictionsReceiver.KEY_BOOLEAN)) { + mBooleanPref.setChecked(entry.getSelectedState()); + mBooleanEntry = entry; + } else if (entry.getKey().equals(GetRestrictionsReceiver.KEY_CHOICE)) { + mChoicePref.setValue(entry.getSelectedString()); + mChoiceEntry = entry; + } else if (entry.getKey().equals(GetRestrictionsReceiver.KEY_MULTI_SELECT)) { + HashSet<String> set = new HashSet<String>(); + for (String value : entry.getAllSelectedStrings()) { + set.add(value); + } + mMultiPref.setValues(set); + mMultiEntry = entry; + } + } + } else { + mRestrictions = new ArrayList<RestrictionEntry>(); + + // Initializes the boolean restriction entry and updates its corresponding shared + // preference value. + mBooleanEntry = new RestrictionEntry(GetRestrictionsReceiver.KEY_BOOLEAN, + mRestrictionsBundle.getBoolean(GetRestrictionsReceiver.KEY_BOOLEAN, false)); + mBooleanEntry.setType(RestrictionEntry.TYPE_BOOLEAN); + mBooleanPref.setChecked(mBooleanEntry.getSelectedState()); + + // Initializes the single choice restriction entry and updates its corresponding + // shared preference value. + mChoiceEntry = new RestrictionEntry(GetRestrictionsReceiver.KEY_CHOICE, + mRestrictionsBundle.getString(GetRestrictionsReceiver.KEY_CHOICE)); + mChoiceEntry.setType(RestrictionEntry.TYPE_CHOICE); + mChoicePref.setValue(mChoiceEntry.getSelectedString()); + + // Initializes the multi-select restriction entry and updates its corresponding + // shared preference value. + mMultiEntry = new RestrictionEntry(GetRestrictionsReceiver.KEY_MULTI_SELECT, + mRestrictionsBundle.getStringArray( + GetRestrictionsReceiver.KEY_MULTI_SELECT)); + mMultiEntry.setType(RestrictionEntry.TYPE_MULTI_SELECT); + if (mMultiEntry.getAllSelectedStrings() != null) { + HashSet<String> set = new HashSet<String>(); + final String[] values = mRestrictionsBundle.getStringArray( + GetRestrictionsReceiver.KEY_MULTI_SELECT); + if (values != null) { + for (String value : values) { + set.add(value); + } + } + mMultiPref.setValues(set); + } + mRestrictions.add(mBooleanEntry); + mRestrictions.add(mChoiceEntry); + mRestrictions.add(mMultiEntry); + } + // Prepares result to be passed back to the Settings app when the custom restrictions + // activity finishes. + Intent intent = new Intent(getActivity().getIntent()); + intent.putParcelableArrayListExtra(Intent.EXTRA_RESTRICTIONS_LIST, + new ArrayList<RestrictionEntry>(mRestrictions)); + getActivity().setResult(Activity.RESULT_OK, intent); + } + + @Override + public boolean onPreferenceChange(Preference preference, Object newValue) { + if (preference == mBooleanPref) { + mBooleanEntry.setSelectedState((Boolean) newValue); + } else if (preference == mChoicePref) { + mChoiceEntry.setSelectedString((String) newValue); + } else if (preference == mMultiPref) { + String[] selectedStrings = new String[((Set<String>)newValue).size()]; + int i = 0; + for (String value : (Set<String>) newValue) { + selectedStrings[i++] = value; + } + mMultiEntry.setAllSelectedStrings(selectedStrings); + } + + // Saves all the app restriction configuration changes from the custom activity. + Intent intent = new Intent(getActivity().getIntent()); + intent.putParcelableArrayListExtra(Intent.EXTRA_RESTRICTIONS_LIST, + new ArrayList<RestrictionEntry>(mRestrictions)); + getActivity().setResult(Activity.RESULT_OK, intent); + return true; + } +} diff --git a/samples/AppLimits/src/com/example/android/applimits/GetRestrictionsReceiver.java b/samples/AppRestrictions/src/com/example/android/apprestrictions/GetRestrictionsReceiver.java index 0249911e3..bb5a28391 100644 --- a/samples/AppLimits/src/com/example/android/applimits/GetRestrictionsReceiver.java +++ b/samples/AppRestrictions/src/com/example/android/apprestrictions/GetRestrictionsReceiver.java @@ -14,46 +14,52 @@ * limitations under the License. */ -package com.example.android.applimits; +package com.example.android.apprestrictions; import android.app.Activity; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.RestrictionEntry; -import android.content.BroadcastReceiver.PendingResult; import android.content.res.Resources; import android.os.Bundle; +import android.preference.PreferenceManager; import android.util.Log; import java.util.ArrayList; -import java.util.List; public class GetRestrictionsReceiver extends BroadcastReceiver { - private static final String TAG = "AppLimits$GetRestrictionsReceiver"; + private static final String TAG = GetRestrictionsReceiver.class.getSimpleName(); - static final String KEY_CUSTOM = "custom_or_not"; - static final String KEY_CHOICE = "choice"; - static final String KEY_MULTI_SELECT = "multi"; + // Keys for referencing app restriction settings from the platform. + public static final String KEY_BOOLEAN = "boolean_key"; + public static final String KEY_CHOICE = "choice_key"; + public static final String KEY_MULTI_SELECT = "multi_key"; @Override public void onReceive(final Context context, Intent intent) { final PendingResult result = goAsync(); - final Bundle oldRestrictions = + + // If app restriction settings are already created, they will be included in the Bundle + // as key/value pairs. + final Bundle existingRestrictions = intent.getBundleExtra(Intent.EXTRA_RESTRICTIONS_BUNDLE); - Log.i(TAG, "oldRestrictions = " + oldRestrictions); + Log.i(TAG, "existingRestrictions = " + existingRestrictions); + new Thread() { public void run() { - createRestrictions(context, result, oldRestrictions); + createRestrictions(context, result, existingRestrictions); } }.start(); } - public static void populateCustomEntry(Resources res, RestrictionEntry entry) { + // Initializes a boolean type restriction entry. + public static void populateBooleanEntry(Resources res, RestrictionEntry entry) { entry.setType(RestrictionEntry.TYPE_BOOLEAN); - entry.setTitle(res.getString(R.string.custom_or_not_title)); + entry.setTitle(res.getString(R.string.boolean_entry_title)); } + // Initializes a single choice type restriction entry. public static void populateChoiceEntry(Resources res, RestrictionEntry reSingleChoice) { String[] choiceEntries = res.getStringArray(R.array.choice_entry_entries); String[] choiceValues = res.getStringArray(R.array.choice_entry_values); @@ -66,6 +72,7 @@ public class GetRestrictionsReceiver extends BroadcastReceiver { reSingleChoice.setType(RestrictionEntry.TYPE_CHOICE); } + // Initializes a multi-select type restriction entry. public static void populateMultiEntry(Resources res, RestrictionEntry reMultiSelect) { String[] multiEntries = res.getStringArray(R.array.multi_entry_entries); String[] multiValues = res.getStringArray(R.array.multi_entry_values); @@ -78,13 +85,15 @@ public class GetRestrictionsReceiver extends BroadcastReceiver { reMultiSelect.setType(RestrictionEntry.TYPE_MULTI_SELECT); } + // Demonstrates the creation of standard app restriction types: boolean, single choice, and + // multi-select. private ArrayList<RestrictionEntry> initRestrictions(Context context) { ArrayList<RestrictionEntry> newRestrictions = new ArrayList<RestrictionEntry>(); Resources res = context.getResources(); - RestrictionEntry reCustomOrNot = new RestrictionEntry(KEY_CUSTOM, false); - populateCustomEntry(res, reCustomOrNot); - newRestrictions.add(reCustomOrNot); + RestrictionEntry reBoolean = new RestrictionEntry(KEY_BOOLEAN, false); + populateBooleanEntry(res, reBoolean); + newRestrictions.add(reBoolean); RestrictionEntry reSingleChoice = new RestrictionEntry(KEY_CHOICE, (String) null); populateChoiceEntry(res, reSingleChoice); @@ -97,12 +106,16 @@ public class GetRestrictionsReceiver extends BroadcastReceiver { return newRestrictions; } - private void createRestrictions(Context context, PendingResult result, Bundle old) { - Resources res = context.getResources(); - + private void createRestrictions(Context context, PendingResult result, + Bundle existingRestrictions) { + // The incoming restrictions bundle contains key/value pairs representing existing app + // restrictions for this package. In order to retain existing app restrictions, you need to + // construct new restriction entries and then copy in any existing values for the new keys. ArrayList<RestrictionEntry> newEntries = initRestrictions(context); - // If this is the first time, create the default restrictions entries and return them. - if (old == null) { + + // If app restrictions were not previously configured for the package, create the default + // restrictions entries and return them. + if (existingRestrictions == null) { Bundle extras = new Bundle(); extras.putParcelableArrayList(Intent.EXTRA_RESTRICTIONS_LIST, newEntries); result.setResult(Activity.RESULT_OK, null, extras); @@ -110,28 +123,38 @@ public class GetRestrictionsReceiver extends BroadcastReceiver { return; } - boolean custom = old.getBoolean(KEY_CUSTOM, false); + // Retains current restriction settings by transferring existing restriction entries to + // new ones. for (RestrictionEntry entry : newEntries) { final String key = entry.getKey(); - if (KEY_CUSTOM.equals(key)) { - entry.setSelectedState(custom); + if (KEY_BOOLEAN.equals(key)) { + entry.setSelectedState(existingRestrictions.getBoolean(KEY_BOOLEAN)); } else if (KEY_CHOICE.equals(key)) { - if (old.containsKey(KEY_CHOICE)) { - entry.setSelectedString(old.getString(KEY_CHOICE)); + if (existingRestrictions.containsKey(KEY_CHOICE)) { + entry.setSelectedString(existingRestrictions.getString(KEY_CHOICE)); } } else if (KEY_MULTI_SELECT.equals(key)) { - if (old.containsKey(KEY_MULTI_SELECT)) { - entry.setAllSelectedStrings(old.getStringArray(key)); + if (existingRestrictions.containsKey(KEY_MULTI_SELECT)) { + entry.setAllSelectedStrings(existingRestrictions.getStringArray(key)); } } } - Bundle extras = new Bundle(); - if (custom) { - Intent customIntent = new Intent(); + final Bundle extras = new Bundle(); + + // This path demonstrates the use of a custom app restriction activity instead of standard + // types. When a custom activity is set, the standard types will not be available under + // app restriction settings. + // + // If your app has an existing activity for app restriction configuration, you can set it + // up with the intent here. + if (PreferenceManager.getDefaultSharedPreferences(context) + .getBoolean(MainActivity.CUSTOM_CONFIG_KEY, false)) { + final Intent customIntent = new Intent(); customIntent.setClass(context, CustomRestrictionsActivity.class); extras.putParcelable(Intent.EXTRA_RESTRICTIONS_INTENT, customIntent); } + extras.putParcelableArrayList(Intent.EXTRA_RESTRICTIONS_LIST, newEntries); result.setResult(Activity.RESULT_OK, null, extras); result.finish(); diff --git a/samples/AppRestrictions/src/com/example/android/apprestrictions/MainActivity.java b/samples/AppRestrictions/src/com/example/android/apprestrictions/MainActivity.java new file mode 100644 index 000000000..57c443906 --- /dev/null +++ b/samples/AppRestrictions/src/com/example/android/apprestrictions/MainActivity.java @@ -0,0 +1,131 @@ +/* + * 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.example.android.apprestrictions; + +import android.app.Activity; +import android.content.Context; +import android.content.SharedPreferences; +import android.os.Bundle; +import android.os.UserManager; +import android.preference.PreferenceManager; +import android.view.View; +import android.widget.CheckBox; +import android.widget.TextView; + +/** + * This is the main user interface of the App Restrictions sample app. It demonstrates the use + * of the App Restriction feature, which is available on Android 4.3 and above tablet devices + * with the multiuser feature. + * + * When launched under the primary User account, you can toggle between standard app restriction + * types and custom. When launched under a restricted profile, this activity displays app + * restriction settings, if available. + * + * Follow these steps to exercise the feature: + * 1. If this is the primary user, go to Settings > Users. + * 2. Create a restricted profile, if one doesn't exist already. + * 3. Open the profile settings, locate the sample app, and tap the app restriction settings + * icon. Configure app restrictions for the app. + * 4. In the lock screen, switch to the user's restricted profile, launch this sample app, + * and see the configured app restrictions displayed. + */ +public class MainActivity extends Activity { + private Bundle mRestrictionsBundle; + + // Checkbox to indicate whether custom or standard app restriction types are selected. + private CheckBox mCustomConfig; + + public static final String CUSTOM_CONFIG_KEY = "custom_config"; + + private TextView mMultiEntryValue; + private TextView mChoiceEntryValue; + private TextView mBooleanEntryValue; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + // Sets up user interface elements. + setContentView(R.layout.main); + + mCustomConfig = (CheckBox) findViewById(R.id.custom_app_limits); + final boolean customChecked = + PreferenceManager.getDefaultSharedPreferences(this).getBoolean( + CUSTOM_CONFIG_KEY, false); + if (customChecked) mCustomConfig.setChecked(true); + + mMultiEntryValue = (TextView) findViewById(R.id.multi_entry_id); + mChoiceEntryValue = (TextView) findViewById(R.id.choice_entry_id); + mBooleanEntryValue = (TextView) findViewById(R.id.boolean_entry_id); + } + + @Override + protected void onResume() { + super.onResume(); + + // If app restrictions are set for this package, when launched from a restricted profile, + // the settings are available in the returned Bundle as key/value pairs. + mRestrictionsBundle = + ((UserManager) getSystemService(Context.USER_SERVICE)) + .getApplicationRestrictions(getPackageName()); + if (mRestrictionsBundle == null) { + mRestrictionsBundle = new Bundle(); + } + + // Reads and displays values from a boolean type restriction entry, if available. + // An app can utilize these settings to restrict its content under a restricted profile. + final String booleanRestrictionValue = + mRestrictionsBundle.containsKey(GetRestrictionsReceiver.KEY_BOOLEAN) ? + mRestrictionsBundle.getBoolean(GetRestrictionsReceiver.KEY_BOOLEAN) + "": + getString(R.string.na); + mBooleanEntryValue.setText(booleanRestrictionValue); + + // Reads and displays values from a single choice restriction entry, if available. + final String singleChoiceRestrictionValue = + mRestrictionsBundle.containsKey(GetRestrictionsReceiver.KEY_CHOICE) ? + mRestrictionsBundle.getString(GetRestrictionsReceiver.KEY_CHOICE) : + getString(R.string.na); + mChoiceEntryValue.setText(singleChoiceRestrictionValue); + + // Reads and displays values from a multi-select restriction entry, if available. + final String[] multiSelectValues = + mRestrictionsBundle.getStringArray(GetRestrictionsReceiver.KEY_MULTI_SELECT); + if (multiSelectValues == null || multiSelectValues.length == 0) { + mMultiEntryValue.setText(getString(R.string.na)); + } else { + String tempValue = ""; + for (String value : multiSelectValues) { + tempValue = tempValue + value + " "; + } + mMultiEntryValue.setText(tempValue); + } + } + + /** + * Saves custom app restriction to the shared preference. + * + * This flag is used by {@code GetRestrictionsReceiver} to determine if a custom app + * restriction activity should be used. + * + * @param view + */ + public void onCustomClicked(View view) { + final SharedPreferences.Editor editor = + PreferenceManager.getDefaultSharedPreferences(this).edit(); + editor.putBoolean(CUSTOM_CONFIG_KEY, mCustomConfig.isChecked()).commit(); + } +} |