• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2014 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.tv.settings.users;
18 
19 import android.app.Activity;
20 import android.app.Fragment;
21 import android.content.BroadcastReceiver;
22 import android.content.Context;
23 import android.content.Intent;
24 import android.content.RestrictionEntry;
25 import android.os.Bundle;
26 import android.os.UserHandle;
27 import android.os.UserManager;
28 import android.text.TextUtils;
29 import android.util.Log;
30 
31 import com.android.tv.settings.R;
32 import com.android.tv.settings.dialog.DialogFragment;
33 import com.android.tv.settings.dialog.DialogFragment.Action;
34 
35 import java.util.ArrayList;
36 import java.util.Arrays;
37 import java.util.HashSet;
38 import java.util.List;
39 
40 /**
41  * Handles all aspects of DialogFragment Actions for setting individual app restrictions.
42  */
43 class AppRestrictionsManager implements Action.Listener {
44 
45     interface Listener {
onRestrictionActionsLoaded(String packageName, ArrayList<Action> actions)46         void onRestrictionActionsLoaded(String packageName, ArrayList<Action> actions);
47     }
48 
49     private static final boolean DEBUG = false;
50     private static final String TAG = "RestrictedProfile";
51 
52     private static final String EXTRA_PACKAGE_NAME = "AppRestrictionsManager.package_name";
53     private static final String EXTRA_RESTRICTIONS = "AppRestrictionsManager.restrictions";
54     private static final String EXTRA_USER_HANDLE = "user_handle";
55     private static final String EXTRA_ENABLED = "enabled";
56     private static final String EXTRA_RESTRICTION_KEY = "restriction_key";
57     private static final String EXTRA_CHOICE_VALUE = "choice_value";
58     private static final String ACTION_CUSTOM_CONFIGURATION = "action_custom_configuration";
59     private static final String ACTION_TRUE = "action_true";
60     private static final String ACTION_FALSE = "action_false";
61     private static final String ACTION_CHANGE_RESTRICTION = "action_change_restriction";
62     private static final String ACTION_CHOICE = "action_choice";
63     private static final String ACTION_MULTI_CHOICE = "action_multi_choice";
64     private static final int MUTUALLY_EXCLUSIVE_CHOICE_CHECK_SET_ID = 1;
65 
66     private final Fragment mFragment;
67     private final UserManager mUserManager;
68     private final UserHandle mUserHandle;
69     private final String mPackageName;
70     private final Listener mListener;
71     private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
72         private static final String CUSTOM_RESTRICTIONS_INTENT = Intent.EXTRA_RESTRICTIONS_INTENT;
73 
74         @Override
75         public void onReceive(Context context, Intent intent) {
76             Bundle results = getResultExtras(true);
77             mRestrictions = results.getParcelableArrayList(Intent.EXTRA_RESTRICTIONS_LIST);
78             mRestrictionsIntent = results.getParcelable(CUSTOM_RESTRICTIONS_INTENT);
79 
80             if (mRestrictions != null && mRestrictionsIntent == null) {
81                 saveRestrictions();
82             } else if (mRestrictionsIntent != null) {
83                 getRestrictionActions();
84             }
85         }
86     };
87 
88     private ArrayList<RestrictionEntry> mRestrictions;
89     private Intent mRestrictionsIntent;
90     private DialogFragment mCurrentDialogFragment;
91 
92     /**
93      * @param fragment THe fragment for which DialogFragment actions are being managed.
94      * @param userHandle the user whose app restrictions are being set.
95      * @param userManager the user manager for setting app restrictions.
96      * @param packageName settings' package name (for special case restrictions).
97      * @param listener a listener for when restriction actions are ready to be displayed.
98      */
AppRestrictionsManager(Fragment fragment, UserHandle userHandle, UserManager userManager, String packageName, Listener listener)99     AppRestrictionsManager(Fragment fragment, UserHandle userHandle, UserManager userManager,
100             String packageName, Listener listener) {
101         mFragment = fragment;
102         mUserHandle = userHandle;
103         mUserManager = userManager;
104         mPackageName = packageName;
105         mListener = listener;
106     }
107 
loadRestrictionActions()108     void loadRestrictionActions() {
109         if (mPackageName.equals(mFragment.getActivity().getPackageName())) {
110             // Settings, fake it by using user restrictions
111             mRestrictions = RestrictionUtils.getRestrictions(mFragment.getActivity(), mUserHandle);
112             mRestrictionsIntent = null;
113             getRestrictionActions();
114         } else {
115             requestRestrictionsForApp();
116         }
117     }
118 
119     @Override
onActionClicked(Action action)120     public void onActionClicked(Action action) {
121         String restrictionEntryKey = action.getIntent().getStringExtra(EXTRA_RESTRICTION_KEY);
122         RestrictionEntry entry = restrictionEntryKey != null ? findRestriction(restrictionEntryKey)
123                 : null;
124 
125         if (ACTION_CUSTOM_CONFIGURATION.equals(action.getKey())) {
126             mFragment.startActivityForResult(action.getIntent(), 1);
127         } else if (ACTION_CHANGE_RESTRICTION.equals(action.getKey())) {
128             ArrayList<Action> actions = new ArrayList<>();
129             switch (entry.getType()) {
130                 case RestrictionEntry.TYPE_BOOLEAN:
131                     actions.add(new Action.Builder()
132                             .key(ACTION_TRUE)
133                             .title(Boolean.toString(true))
134                             .checked(entry.getSelectedState())
135                             .checkSetId(MUTUALLY_EXCLUSIVE_CHOICE_CHECK_SET_ID)
136                             .intent(action.getIntent())
137                             .build());
138                     actions.add(new Action.Builder()
139                             .key(ACTION_FALSE)
140                             .title(Boolean.toString(false))
141                             .checked(!entry.getSelectedState())
142                             .checkSetId(MUTUALLY_EXCLUSIVE_CHOICE_CHECK_SET_ID)
143                             .intent(action.getIntent())
144                             .build());
145                     break;
146                 case RestrictionEntry.TYPE_CHOICE:
147                 case RestrictionEntry.TYPE_CHOICE_LEVEL:
148                 {
149                     String value = entry.getSelectedString();
150                     if (value == null) {
151                         value = entry.getDescription();
152                     }
153                     String[] choiceEntries = entry.getChoiceEntries();
154                     String[] choiceValues = entry.getChoiceValues();
155                     boolean useValue = (choiceEntries == null
156                             || choiceEntries.length != choiceValues.length);
157                     for (int i = 0; i < choiceValues.length; i++) {
158                         String choiceValue = choiceValues[i];
159                         String title = useValue ? choiceValue : choiceEntries[i];
160                         Intent intent = new Intent(action.getIntent());
161                         intent.putExtra(EXTRA_CHOICE_VALUE, choiceValue);
162                         actions.add(new Action.Builder()
163                                 .key(ACTION_CHOICE)
164                                 .title(title)
165                                 .checked(choiceValue.equals(value))
166                                 .checkSetId(MUTUALLY_EXCLUSIVE_CHOICE_CHECK_SET_ID)
167                                 .intent(intent)
168                                 .build());
169                     }
170                 }
171                     break;
172                 case RestrictionEntry.TYPE_MULTI_SELECT:
173                 {
174                     List<String> selectedChoiceValues = Arrays.asList(
175                             entry.getAllSelectedStrings());
176                     String[] choiceEntries = entry.getChoiceEntries();
177                     String[] choiceValues = entry.getChoiceValues();
178                     boolean useValues = (choiceEntries == null
179                             || choiceEntries.length != choiceValues.length);
180                     for (int i = 0; i < choiceValues.length; i++) {
181                         String choiceValue = choiceValues[i];
182                         String title = useValues ? choiceValue : choiceEntries[i];
183                         Intent intent = new Intent(action.getIntent());
184                         intent.putExtra(EXTRA_CHOICE_VALUE, choiceValue);
185                         actions.add(new Action.Builder()
186                                 .key(ACTION_MULTI_CHOICE)
187                                 .title(title)
188                                 .checked(selectedChoiceValues.contains(choiceValue))
189                                 .intent(intent)
190                                 .build());
191                     }
192                 }
193                     break;
194                 case RestrictionEntry.TYPE_NULL:
195                 default:
196             }
197 
198             if (!actions.isEmpty()) {
199                 mCurrentDialogFragment = new DialogFragment.Builder()
200                         .title(entry.getTitle())
201                         .description(entry.getDescription())
202                         .iconResourceId(RestrictedProfileDialogFragment.getIconResource())
203                         .iconBackgroundColor(
204                                 mFragment.getActivity().getResources()
205                                         .getColor(R.color.icon_background))
206                         .actions(actions).build();
207                 mCurrentDialogFragment.setListener(this);
208                 DialogFragment.add(mFragment.getFragmentManager(), mCurrentDialogFragment);
209 
210             }
211         } else if (ACTION_TRUE.equals(action.getKey())) {
212             entry.setSelectedState(true);
213             saveRestrictions();
214         } else if (ACTION_FALSE.equals(action.getKey())) {
215             entry.setSelectedState(false);
216             saveRestrictions();
217         } else if (ACTION_CHOICE.equals(action.getKey())) {
218             entry.setSelectedString(getChoiceValue(action));
219             saveRestrictions();
220         } else if (ACTION_MULTI_CHOICE.equals(action.getKey())) {
221 
222             action.setChecked(!action.isChecked());
223             if (mCurrentDialogFragment != null) {
224                 mCurrentDialogFragment.setActions(mCurrentDialogFragment.getActions());
225             }
226             HashSet<String> selectedChoiceValues = new HashSet<>();
227             selectedChoiceValues.addAll(Arrays.asList(entry.getAllSelectedStrings()));
228 
229             if (action.isChecked()) {
230                 selectedChoiceValues.add(getChoiceValue(action));
231             } else {
232                 selectedChoiceValues.remove(getChoiceValue(action));
233             }
234             entry.setAllSelectedStrings(
235                     selectedChoiceValues.toArray(new String[selectedChoiceValues.size()]));
236             saveRestrictions();
237         }
238     }
239 
onActivityResult(int requestCode, int resultCode, Intent data)240     void onActivityResult(int requestCode, int resultCode, Intent data) {
241         if (resultCode == Activity.RESULT_OK) {
242             ArrayList<RestrictionEntry> list =
243                     data.getParcelableArrayListExtra(Intent.EXTRA_RESTRICTIONS_LIST);
244             Bundle bundle = data.getBundleExtra(Intent.EXTRA_RESTRICTIONS_BUNDLE);
245             if (list != null) {
246                 // If there's a valid result, persist it to the user manager.
247                 mUserManager.setApplicationRestrictions(mPackageName,
248                         RestrictionUtils.restrictionsToBundle(list), mUserHandle);
249             } else if (bundle != null) {
250                 // If there's a valid result, persist it to the user manager.
251                 mUserManager.setApplicationRestrictions(mPackageName, bundle, mUserHandle);
252             }
253             loadRestrictionActions();
254         }
255     }
256 
findRestriction(String key)257     private RestrictionEntry findRestriction(String key) {
258         for (RestrictionEntry entry : mRestrictions) {
259             if (entry.getKey().equals(key)) {
260                 return entry;
261             }
262         }
263         Log.wtf(TAG, "Couldn't find the restriction to set!");
264         return null;
265     }
266 
getChoiceValue(Action action)267     private String getChoiceValue(Action action) {
268         return action.getIntent().getStringExtra(EXTRA_CHOICE_VALUE);
269     }
270 
271     /**
272      * Send a broadcast to the app to query its restrictions
273      */
requestRestrictionsForApp()274     private void requestRestrictionsForApp() {
275         Bundle oldEntries = mUserManager.getApplicationRestrictions(mPackageName, mUserHandle);
276         Intent intent = new Intent(Intent.ACTION_GET_RESTRICTION_ENTRIES);
277         intent.setPackage(mPackageName);
278         intent.putExtra(Intent.EXTRA_RESTRICTIONS_BUNDLE, oldEntries);
279         intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
280         mFragment.getActivity().sendOrderedBroadcast(intent, null, mBroadcastReceiver, null,
281                 Activity.RESULT_OK, null, null);
282     }
283 
getRestrictionActions()284     private void getRestrictionActions() {
285         ArrayList<Action> actions = new ArrayList<>();
286 
287         if (mRestrictionsIntent != null) {
288             actions.add(new Action.Builder()
289                     .key(ACTION_CUSTOM_CONFIGURATION)
290                     .title(mFragment.getActivity().getString(
291                             R.string.restricted_profile_customize_restrictions))
292                     .intent(mRestrictionsIntent)
293                     .hasNext(true)
294                     .build());
295         }
296 
297         if (mRestrictions != null) {
298             for (RestrictionEntry entry : mRestrictions) {
299                 Intent data = new Intent().putExtra(EXTRA_RESTRICTION_KEY, entry.getKey());
300                 switch (entry.getType()) {
301                     case RestrictionEntry.TYPE_BOOLEAN:
302                         actions.add(new Action.Builder()
303                                 .key(ACTION_CHANGE_RESTRICTION)
304                                 .title(entry.getTitle())
305                                 .description(mFragment.getActivity().getString(
306                                         R.string.restriction_description, entry.getDescription(),
307                                         Boolean.toString(entry.getSelectedState())))
308                                 .hasNext(mRestrictionsIntent == null)
309                                 .infoOnly(mRestrictionsIntent != null)
310                                 .intent(data)
311                                 .multilineDescription(true)
312                                 .build());
313                         break;
314                     case RestrictionEntry.TYPE_CHOICE:
315                     case RestrictionEntry.TYPE_CHOICE_LEVEL:
316                         String value = entry.getSelectedString();
317                         if (value == null) {
318                             value = entry.getDescription();
319                         }
320                         actions.add(new Action.Builder()
321                                 .key(ACTION_CHANGE_RESTRICTION)
322                                 .title(entry.getTitle())
323                                 .description(mFragment.getActivity().getString(
324                                         R.string.restriction_description,
325                                         entry.getDescription(), findInArray(
326                                                 entry.getChoiceEntries(), entry.getChoiceValues(),
327                                                 value)))
328                                 .hasNext(mRestrictionsIntent == null)
329                                 .infoOnly(mRestrictionsIntent != null)
330                                 .intent(data)
331                                 .multilineDescription(true)
332                                 .build());
333                         break;
334                     case RestrictionEntry.TYPE_MULTI_SELECT:
335                         actions.add(new Action.Builder()
336                                 .key(ACTION_CHANGE_RESTRICTION)
337                                 .title(entry.getTitle())
338                                 .description(mFragment.getActivity().getString(
339                                         R.string.restriction_description,
340                                         entry.getDescription(), TextUtils.join(
341                                                 ", ", findSelectedStrings(entry.getChoiceEntries(),
342                                                         entry.getChoiceValues(),
343                                                         entry.getAllSelectedStrings()))))
344                                 .hasNext(mRestrictionsIntent == null)
345                                 .infoOnly(mRestrictionsIntent != null)
346                                 .intent(data)
347                                 .multilineDescription(true)
348                                 .build());
349                         break;
350                     case RestrictionEntry.TYPE_NULL:
351                     default:
352                 }
353             }
354         }
355 
356         mListener.onRestrictionActionsLoaded(mPackageName, actions);
357     }
358 
findInArray(String[] choiceEntries, String[] choiceValues, String selectedString)359     private String findInArray(String[] choiceEntries, String[] choiceValues,
360             String selectedString) {
361         if (choiceEntries == null || choiceValues.length != choiceEntries.length) {
362             return selectedString;
363         }
364         for (int i = 0; i < choiceValues.length; i++) {
365             if (choiceValues[i].equals(selectedString)) {
366                 return choiceEntries[i];
367             }
368         }
369         return selectedString;
370     }
371 
findSelectedStrings(String[] choiceEntries, String[] choiceValues, String[] selectedStrings)372     private String[] findSelectedStrings(String[] choiceEntries, String[] choiceValues,
373             String[] selectedStrings) {
374         if (choiceEntries == null || choiceValues.length != choiceEntries.length) {
375             return selectedStrings;
376         }
377         String[] selectedStringsMapped = new String[selectedStrings.length];
378         for (int i = 0; i < selectedStrings.length; i++) {
379             selectedStringsMapped[i] = selectedStrings[i];
380             for (int j = 0; j < choiceValues.length; j++) {
381                 if (choiceValues[j].equals(selectedStrings[i])) {
382                     selectedStringsMapped[i] = choiceEntries[j];
383                 }
384             }
385         }
386         return selectedStringsMapped;
387     }
388 
saveRestrictions()389     private void saveRestrictions() {
390         getRestrictionActions();
391         if (mPackageName.equals(mFragment.getActivity().getPackageName())) {
392             RestrictionUtils.setRestrictions(mFragment.getActivity(), mRestrictions, mUserHandle);
393         } else {
394             Bundle bundle = RestrictionUtils.restrictionsToBundle(mRestrictions);
395             mUserManager.setApplicationRestrictions(mPackageName, bundle, mUserHandle);
396         }
397     }
398 }
399