1*90c8c64dSAndroid Build Coastguard Worker /*
2*90c8c64dSAndroid Build Coastguard Worker  * Copyright (C) 2013 The Android Open Source Project
3*90c8c64dSAndroid Build Coastguard Worker  *
4*90c8c64dSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*90c8c64dSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*90c8c64dSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*90c8c64dSAndroid Build Coastguard Worker  *
8*90c8c64dSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*90c8c64dSAndroid Build Coastguard Worker  *
10*90c8c64dSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*90c8c64dSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*90c8c64dSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*90c8c64dSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*90c8c64dSAndroid Build Coastguard Worker  * limitations under the License.
15*90c8c64dSAndroid Build Coastguard Worker  */
16*90c8c64dSAndroid Build Coastguard Worker 
17*90c8c64dSAndroid Build Coastguard Worker package com.example.android.apprestrictions;
18*90c8c64dSAndroid Build Coastguard Worker 
19*90c8c64dSAndroid Build Coastguard Worker import android.app.Activity;
20*90c8c64dSAndroid Build Coastguard Worker import android.content.Context;
21*90c8c64dSAndroid Build Coastguard Worker import android.content.Intent;
22*90c8c64dSAndroid Build Coastguard Worker import android.content.RestrictionEntry;
23*90c8c64dSAndroid Build Coastguard Worker import android.os.Bundle;
24*90c8c64dSAndroid Build Coastguard Worker import android.os.UserManager;
25*90c8c64dSAndroid Build Coastguard Worker import android.preference.CheckBoxPreference;
26*90c8c64dSAndroid Build Coastguard Worker import android.preference.ListPreference;
27*90c8c64dSAndroid Build Coastguard Worker import android.preference.MultiSelectListPreference;
28*90c8c64dSAndroid Build Coastguard Worker import android.preference.Preference;
29*90c8c64dSAndroid Build Coastguard Worker import android.preference.PreferenceFragment;
30*90c8c64dSAndroid Build Coastguard Worker 
31*90c8c64dSAndroid Build Coastguard Worker import java.util.ArrayList;
32*90c8c64dSAndroid Build Coastguard Worker import java.util.Collections;
33*90c8c64dSAndroid Build Coastguard Worker import java.util.HashSet;
34*90c8c64dSAndroid Build Coastguard Worker import java.util.List;
35*90c8c64dSAndroid Build Coastguard Worker import java.util.Set;
36*90c8c64dSAndroid Build Coastguard Worker 
37*90c8c64dSAndroid Build Coastguard Worker /**
38*90c8c64dSAndroid Build Coastguard Worker  * This fragment is included in {@code CustomRestrictionsActivity}.  It demonstrates how an app
39*90c8c64dSAndroid Build Coastguard Worker  * can integrate its own custom app restriction settings with the restricted profile feature.
40*90c8c64dSAndroid Build Coastguard Worker  *
41*90c8c64dSAndroid Build Coastguard Worker  * This sample app maintains custom app restriction settings in shared preferences.  Your app
42*90c8c64dSAndroid Build Coastguard Worker  * can use other methods to maintain the settings.  When this activity is invoked
43*90c8c64dSAndroid Build Coastguard Worker  * (from Settings > Users > Restricted Profile), the shared preferences are used to initialize
44*90c8c64dSAndroid Build Coastguard Worker  * the custom configuration on the user interface.
45*90c8c64dSAndroid Build Coastguard Worker  *
46*90c8c64dSAndroid Build Coastguard Worker  * Three sample input types are shown: checkbox, single-choice, and multi-choice.  When the
47*90c8c64dSAndroid Build Coastguard Worker  * settings are modified by the user, the corresponding restriction entries are saved in the
48*90c8c64dSAndroid Build Coastguard Worker  * platform.  The saved restriction entries are retrievable when the app is launched under a
49*90c8c64dSAndroid Build Coastguard Worker  * restricted profile.
50*90c8c64dSAndroid Build Coastguard Worker  */
51*90c8c64dSAndroid Build Coastguard Worker public class CustomRestrictionsFragment extends PreferenceFragment
52*90c8c64dSAndroid Build Coastguard Worker         implements Preference.OnPreferenceChangeListener {
53*90c8c64dSAndroid Build Coastguard Worker 
54*90c8c64dSAndroid Build Coastguard Worker     // Shared preference key for the boolean restriction.
55*90c8c64dSAndroid Build Coastguard Worker     private static final String KEY_BOOLEAN_PREF = "pref_boolean";
56*90c8c64dSAndroid Build Coastguard Worker     // Shared preference key for the single-select restriction.
57*90c8c64dSAndroid Build Coastguard Worker     private static final String KEY_CHOICE_PREF = "pref_choice";
58*90c8c64dSAndroid Build Coastguard Worker     // Shared preference key for the multi-select restriction.
59*90c8c64dSAndroid Build Coastguard Worker     private static final String KEY_MULTI_PREF = "pref_multi";
60*90c8c64dSAndroid Build Coastguard Worker 
61*90c8c64dSAndroid Build Coastguard Worker 
62*90c8c64dSAndroid Build Coastguard Worker     private List<RestrictionEntry> mRestrictions;
63*90c8c64dSAndroid Build Coastguard Worker     private Bundle mRestrictionsBundle;
64*90c8c64dSAndroid Build Coastguard Worker 
65*90c8c64dSAndroid Build Coastguard Worker     // Shared preferences for each of the sample input types.
66*90c8c64dSAndroid Build Coastguard Worker     private CheckBoxPreference mBooleanPref;
67*90c8c64dSAndroid Build Coastguard Worker     private ListPreference mChoicePref;
68*90c8c64dSAndroid Build Coastguard Worker     private MultiSelectListPreference mMultiPref;
69*90c8c64dSAndroid Build Coastguard Worker 
70*90c8c64dSAndroid Build Coastguard Worker     // Restriction entries for each of the sample input types.
71*90c8c64dSAndroid Build Coastguard Worker     private RestrictionEntry mBooleanEntry;
72*90c8c64dSAndroid Build Coastguard Worker     private RestrictionEntry mChoiceEntry;
73*90c8c64dSAndroid Build Coastguard Worker     private RestrictionEntry mMultiEntry;
74*90c8c64dSAndroid Build Coastguard Worker 
75*90c8c64dSAndroid Build Coastguard Worker     @Override
onCreate(Bundle savedInstanceState)76*90c8c64dSAndroid Build Coastguard Worker     public void onCreate(Bundle savedInstanceState) {
77*90c8c64dSAndroid Build Coastguard Worker         super.onCreate(savedInstanceState);
78*90c8c64dSAndroid Build Coastguard Worker         addPreferencesFromResource(R.xml.custom_prefs);
79*90c8c64dSAndroid Build Coastguard Worker 
80*90c8c64dSAndroid Build Coastguard Worker         // This sample app uses shared preferences to maintain app restriction settings.  Your app
81*90c8c64dSAndroid Build Coastguard Worker         // can use other methods to maintain the settings.
82*90c8c64dSAndroid Build Coastguard Worker         mBooleanPref = (CheckBoxPreference) findPreference(KEY_BOOLEAN_PREF);
83*90c8c64dSAndroid Build Coastguard Worker         mChoicePref = (ListPreference) findPreference(KEY_CHOICE_PREF);
84*90c8c64dSAndroid Build Coastguard Worker         mMultiPref = (MultiSelectListPreference) findPreference(KEY_MULTI_PREF);
85*90c8c64dSAndroid Build Coastguard Worker 
86*90c8c64dSAndroid Build Coastguard Worker         mBooleanPref.setOnPreferenceChangeListener(this);
87*90c8c64dSAndroid Build Coastguard Worker         mChoicePref.setOnPreferenceChangeListener(this);
88*90c8c64dSAndroid Build Coastguard Worker         mMultiPref.setOnPreferenceChangeListener(this);
89*90c8c64dSAndroid Build Coastguard Worker 
90*90c8c64dSAndroid Build Coastguard Worker         setRetainInstance(true);
91*90c8c64dSAndroid Build Coastguard Worker     }
92*90c8c64dSAndroid Build Coastguard Worker 
93*90c8c64dSAndroid Build Coastguard Worker     @Override
onActivityCreated(Bundle savedInstanceState)94*90c8c64dSAndroid Build Coastguard Worker     public void onActivityCreated(Bundle savedInstanceState) {
95*90c8c64dSAndroid Build Coastguard Worker         super.onActivityCreated(savedInstanceState);
96*90c8c64dSAndroid Build Coastguard Worker         final Activity activity = getActivity();
97*90c8c64dSAndroid Build Coastguard Worker 
98*90c8c64dSAndroid Build Coastguard Worker         // BEGIN_INCLUDE (GET_CURRENT_RESTRICTIONS)
99*90c8c64dSAndroid Build Coastguard Worker         // Existing app restriction settings, if exist, can be retrieved from the Bundle.
100*90c8c64dSAndroid Build Coastguard Worker         mRestrictionsBundle =
101*90c8c64dSAndroid Build Coastguard Worker                 activity.getIntent().getBundleExtra(Intent.EXTRA_RESTRICTIONS_BUNDLE);
102*90c8c64dSAndroid Build Coastguard Worker 
103*90c8c64dSAndroid Build Coastguard Worker         if (mRestrictionsBundle == null) {
104*90c8c64dSAndroid Build Coastguard Worker             mRestrictionsBundle =
105*90c8c64dSAndroid Build Coastguard Worker                     ((UserManager) activity.getSystemService(Context.USER_SERVICE))
106*90c8c64dSAndroid Build Coastguard Worker                             .getApplicationRestrictions(activity.getPackageName());
107*90c8c64dSAndroid Build Coastguard Worker         }
108*90c8c64dSAndroid Build Coastguard Worker 
109*90c8c64dSAndroid Build Coastguard Worker         if (mRestrictionsBundle == null) {
110*90c8c64dSAndroid Build Coastguard Worker             mRestrictionsBundle = new Bundle();
111*90c8c64dSAndroid Build Coastguard Worker         }
112*90c8c64dSAndroid Build Coastguard Worker 
113*90c8c64dSAndroid Build Coastguard Worker         mRestrictions = activity.getIntent().getParcelableArrayListExtra(
114*90c8c64dSAndroid Build Coastguard Worker                 Intent.EXTRA_RESTRICTIONS_LIST);
115*90c8c64dSAndroid Build Coastguard Worker         // END_INCLUDE (GET_CURRENT_RESTRICTIONS)
116*90c8c64dSAndroid Build Coastguard Worker 
117*90c8c64dSAndroid Build Coastguard Worker         // Transfers the saved values into the preference hierarchy.
118*90c8c64dSAndroid Build Coastguard Worker         if (mRestrictions != null) {
119*90c8c64dSAndroid Build Coastguard Worker             for (RestrictionEntry entry : mRestrictions) {
120*90c8c64dSAndroid Build Coastguard Worker                 if (entry.getKey().equals(GetRestrictionsReceiver.KEY_BOOLEAN)) {
121*90c8c64dSAndroid Build Coastguard Worker                     mBooleanPref.setChecked(entry.getSelectedState());
122*90c8c64dSAndroid Build Coastguard Worker                     mBooleanEntry = entry;
123*90c8c64dSAndroid Build Coastguard Worker                 } else if (entry.getKey().equals(GetRestrictionsReceiver.KEY_CHOICE)) {
124*90c8c64dSAndroid Build Coastguard Worker                     mChoicePref.setValue(entry.getSelectedString());
125*90c8c64dSAndroid Build Coastguard Worker                     mChoiceEntry = entry;
126*90c8c64dSAndroid Build Coastguard Worker                 } else if (entry.getKey().equals(GetRestrictionsReceiver.KEY_MULTI_SELECT)) {
127*90c8c64dSAndroid Build Coastguard Worker                     HashSet<String> set = new HashSet<>();
128*90c8c64dSAndroid Build Coastguard Worker                     Collections.addAll(set, entry.getAllSelectedStrings());
129*90c8c64dSAndroid Build Coastguard Worker                     mMultiPref.setValues(set);
130*90c8c64dSAndroid Build Coastguard Worker                     mMultiEntry = entry;
131*90c8c64dSAndroid Build Coastguard Worker                 }
132*90c8c64dSAndroid Build Coastguard Worker             }
133*90c8c64dSAndroid Build Coastguard Worker         } else {
134*90c8c64dSAndroid Build Coastguard Worker             mRestrictions = new ArrayList<>();
135*90c8c64dSAndroid Build Coastguard Worker 
136*90c8c64dSAndroid Build Coastguard Worker             // Initializes the boolean restriction entry and updates its corresponding shared
137*90c8c64dSAndroid Build Coastguard Worker             // preference value.
138*90c8c64dSAndroid Build Coastguard Worker             mBooleanEntry = new RestrictionEntry(GetRestrictionsReceiver.KEY_BOOLEAN,
139*90c8c64dSAndroid Build Coastguard Worker                     mRestrictionsBundle.getBoolean(GetRestrictionsReceiver.KEY_BOOLEAN, false));
140*90c8c64dSAndroid Build Coastguard Worker             mBooleanEntry.setType(RestrictionEntry.TYPE_BOOLEAN);
141*90c8c64dSAndroid Build Coastguard Worker             mBooleanPref.setChecked(mBooleanEntry.getSelectedState());
142*90c8c64dSAndroid Build Coastguard Worker 
143*90c8c64dSAndroid Build Coastguard Worker             // Initializes the single choice restriction entry and updates its corresponding
144*90c8c64dSAndroid Build Coastguard Worker             // shared preference value.
145*90c8c64dSAndroid Build Coastguard Worker             mChoiceEntry = new RestrictionEntry(GetRestrictionsReceiver.KEY_CHOICE,
146*90c8c64dSAndroid Build Coastguard Worker                     mRestrictionsBundle.getString(GetRestrictionsReceiver.KEY_CHOICE));
147*90c8c64dSAndroid Build Coastguard Worker             mChoiceEntry.setType(RestrictionEntry.TYPE_CHOICE);
148*90c8c64dSAndroid Build Coastguard Worker             mChoicePref.setValue(mChoiceEntry.getSelectedString());
149*90c8c64dSAndroid Build Coastguard Worker 
150*90c8c64dSAndroid Build Coastguard Worker             // Initializes the multi-select restriction entry and updates its corresponding
151*90c8c64dSAndroid Build Coastguard Worker             // shared preference value.
152*90c8c64dSAndroid Build Coastguard Worker             mMultiEntry = new RestrictionEntry(GetRestrictionsReceiver.KEY_MULTI_SELECT,
153*90c8c64dSAndroid Build Coastguard Worker                     mRestrictionsBundle.getStringArray(
154*90c8c64dSAndroid Build Coastguard Worker                             GetRestrictionsReceiver.KEY_MULTI_SELECT));
155*90c8c64dSAndroid Build Coastguard Worker             mMultiEntry.setType(RestrictionEntry.TYPE_MULTI_SELECT);
156*90c8c64dSAndroid Build Coastguard Worker             if (mMultiEntry.getAllSelectedStrings() != null) {
157*90c8c64dSAndroid Build Coastguard Worker                 HashSet<String> set = new HashSet<>();
158*90c8c64dSAndroid Build Coastguard Worker                 final String[] values = mRestrictionsBundle.getStringArray(
159*90c8c64dSAndroid Build Coastguard Worker                         GetRestrictionsReceiver.KEY_MULTI_SELECT);
160*90c8c64dSAndroid Build Coastguard Worker                 if (values != null) {
161*90c8c64dSAndroid Build Coastguard Worker                     Collections.addAll(set, values);
162*90c8c64dSAndroid Build Coastguard Worker                 }
163*90c8c64dSAndroid Build Coastguard Worker                 mMultiPref.setValues(set);
164*90c8c64dSAndroid Build Coastguard Worker             }
165*90c8c64dSAndroid Build Coastguard Worker             mRestrictions.add(mBooleanEntry);
166*90c8c64dSAndroid Build Coastguard Worker             mRestrictions.add(mChoiceEntry);
167*90c8c64dSAndroid Build Coastguard Worker             mRestrictions.add(mMultiEntry);
168*90c8c64dSAndroid Build Coastguard Worker         }
169*90c8c64dSAndroid Build Coastguard Worker         // Prepares result to be passed back to the Settings app when the custom restrictions
170*90c8c64dSAndroid Build Coastguard Worker         // activity finishes.
171*90c8c64dSAndroid Build Coastguard Worker         Intent intent = new Intent(getActivity().getIntent());
172*90c8c64dSAndroid Build Coastguard Worker         intent.putParcelableArrayListExtra(Intent.EXTRA_RESTRICTIONS_LIST,
173*90c8c64dSAndroid Build Coastguard Worker                 new ArrayList<>(mRestrictions));
174*90c8c64dSAndroid Build Coastguard Worker         getActivity().setResult(Activity.RESULT_OK, intent);
175*90c8c64dSAndroid Build Coastguard Worker     }
176*90c8c64dSAndroid Build Coastguard Worker 
177*90c8c64dSAndroid Build Coastguard Worker     @Override
onPreferenceChange(Preference preference, Object newValue)178*90c8c64dSAndroid Build Coastguard Worker     public boolean onPreferenceChange(Preference preference, Object newValue) {
179*90c8c64dSAndroid Build Coastguard Worker         if (preference == mBooleanPref) {
180*90c8c64dSAndroid Build Coastguard Worker             mBooleanEntry.setSelectedState((Boolean) newValue);
181*90c8c64dSAndroid Build Coastguard Worker         } else if (preference == mChoicePref) {
182*90c8c64dSAndroid Build Coastguard Worker             mChoiceEntry.setSelectedString((String) newValue);
183*90c8c64dSAndroid Build Coastguard Worker         } else if (preference == mMultiPref && newValue instanceof Set) {
184*90c8c64dSAndroid Build Coastguard Worker             // newValue is a Set<String>, skip the lint warning.
185*90c8c64dSAndroid Build Coastguard Worker             //noinspection unchecked
186*90c8c64dSAndroid Build Coastguard Worker             String[] selectedStrings = new String[((Set<String>) newValue).size()];
187*90c8c64dSAndroid Build Coastguard Worker             int i = 0;
188*90c8c64dSAndroid Build Coastguard Worker             //noinspection unchecked
189*90c8c64dSAndroid Build Coastguard Worker             for (String value : (Set<String>) newValue) {
190*90c8c64dSAndroid Build Coastguard Worker                 selectedStrings[i++] = value;
191*90c8c64dSAndroid Build Coastguard Worker             }
192*90c8c64dSAndroid Build Coastguard Worker             mMultiEntry.setAllSelectedStrings(selectedStrings);
193*90c8c64dSAndroid Build Coastguard Worker         }
194*90c8c64dSAndroid Build Coastguard Worker 
195*90c8c64dSAndroid Build Coastguard Worker         // Saves all the app restriction configuration changes from the custom activity.
196*90c8c64dSAndroid Build Coastguard Worker         Intent intent = new Intent(getActivity().getIntent());
197*90c8c64dSAndroid Build Coastguard Worker         intent.putParcelableArrayListExtra(Intent.EXTRA_RESTRICTIONS_LIST,
198*90c8c64dSAndroid Build Coastguard Worker                 new ArrayList<>(mRestrictions));
199*90c8c64dSAndroid Build Coastguard Worker         getActivity().setResult(Activity.RESULT_OK, intent);
200*90c8c64dSAndroid Build Coastguard Worker         return true;
201*90c8c64dSAndroid Build Coastguard Worker     }
202*90c8c64dSAndroid Build Coastguard Worker }
203