Restricted Profiles Settings

Yesterday Netflix for Android introduced the Restricted Profiles feature.

It is a very powerful opportunity, but very few apps are using this feature.
Remember that restricted profiles require API 18.

Let's see how to realize it.


It is very simple.
First of all, we need to use a BroadcastReceiver that receives the ACTION_GET_RESTRICTION_ENTRIES intent.

<receiver
  android:name="it.gmariotti.android.examples.restrictedprofile.MyRestrictedProfileBroadcast">
    <intent-filter>
        <action android:name="android.intent.action.GET_RESTRICTION_ENTRIES" />
    </intent-filter>
</receiver>
When we click on the setting icon, our BroadcastReceiver is called.
Our receiver has a EXTRA_RESTRICTIONS_INTENT Bundle which contains the key-value pairs for each restriction.
    @Override
    public void onReceive(final Context context, Intent intent) {

          final Bundle currentRestrictions =
                intent.getBundleExtra(Intent.EXTRA_RESTRICTIONS_BUNDLE); 
In onReceive() method you have to create a RestrictionEntry for each restriction your app provides.

Each RestrictionEntry defines a restriction title, description, and one of the following data types:
An example for a boolean value:
    RestrictionEntry entry1 = new RestrictionEntry(KEY_BOOLEAN, true);  //default value!
    entry1.setTitle(context.getString(R.string.entry1_title));
    entry1.setDescription(context.getString(R.string.entry1_description));
    entry1.setType(RestrictionEntry.TYPE_BOOLEAN);
If you want to set the current value you can use something like this::
    //Retrieve current value 
    if (currentRestrictions != null) {
         entry1.setSelectedState(currentRestrictions.getBoolean(KEY_BOOLEAN, true));
    }

An example for a multiple choices that are mutually exclusive:
    RestrictionEntry entry2 = new RestrictionEntry(KEY_CHOICE, (String) null);
    entry2.setTitle(context.getString(R.string.entry2_title));
    entry2.setDescription(context.getString(R.string.entry2_description));
    entry2.setType(RestrictionEntry.TYPE_CHOICE);
    entry2.setChoiceEntries(context, R.array.choice_entries);

    Resources res = context.getResources();
    String[] values = res.getStringArray(R.array.choice_values);
    entry2.setChoiceValues(values);
If you want to set the current value you can use something like this:
    //Retrieve current value
    if (currentRestrictions != null) {
         if (currentRestrictions.containsKey(KEY_CHOICE)) {
              entry2.setSelectedString(currentRestrictions.getString(KEY_CHOICE));
         } else {
              entry2.setSelectedString(values[0]); //Default
         }
   }

An example for a multiple choices that are not mutually exclusive:
     RestrictionEntry entry3 = new RestrictionEntry(KEY_MULTI_SELECT, (String[]) null);
     entry3.setTitle(context.getString(R.string.entry3_title));
     entry3.setDescription(context.getString(R.string.entry3_description));
     entry3.setType(RestrictionEntry.TYPE_MULTI_SELECT);
     entry3.setChoiceEntries(context, R.array.choice_entries);

     entry3.setChoiceValues(values);
If you want to set the current value you can use something like this:
     String[] selected= new String[1];
     selected[0]= values[0];
     //Retrieve current value
     if (currentRestrictions != null) {
          if (currentRestrictions.containsKey(KEY_MULTI_SELECT)) {
               entry3.setAllSelectedStrings(currentRestrictions.getStringArray(KEY_MULTI_SELECT));
          } else {
               entry3.setAllSelectedStrings(selected); //Default
          }
      }

Finally you have to put all the RestrictionEntry objects into an ArrayList and put it into the broadcast receiver's result as the value for the EXTRA_RESTRICTIONS_LIST extra.
    @Override
    public void onReceive(final Context context, Intent intent) {

        final PendingResult result = goAsync();

        final Bundle currentRestrictions =
                intent.getBundleExtra(Intent.EXTRA_RESTRICTIONS_BUNDLE);

        new Thread() {
            public void run() {
                ArrayList list = initRestrictionEntries(context, currentRestrictions);

                Bundle extras = new Bundle();
                extras.putParcelableArrayList(Intent.EXTRA_RESTRICTIONS_LIST, list);
                result.setResult(Activity.RESULT_OK, null, extras);
                result.finish();
                return;
            }
        }.start();

    }
Remember that onReceive method will run in the main activity thread, so it is useful to use a Thread to read and set the values.

The last step is to read this value from your app by calling the getApplicationRestrictions method.
   Bundle mRestrictionsBundle =
         ((UserManager) getSystemService(Context.USER_SERVICE))
                .getApplicationRestrictions(getPackageName());
Pay attention: restrictions are defined for each restricted profile.So when you open your app, you are reading the current restrictions for the current profile.
If the app is running in the main profile, you will receive an empty Bundle.

   boolean value=mRestrictionsBundle.getBoolean(MyRestrictedProfileBroadcast.KEY_BOOLEAN);
   String choice=(mRestrictionsBundle.getString(MyRestrictedProfileBroadcast.KEY_CHOICE);
   String[] values = mRestrictionsBundle.getStringArray
                     (MyRestrictedProfileBroadcast.KEY_MULTI_SELECT);


You can get code from GitHub:

Comments

Popular posts from this blog

AntiPattern: freezing a UI with Broadcast Receiver

How to centralize the support libraries dependencies in gradle

NotificationListenerService and kitkat