Home | History | Annotate | Download | only in com.example.android.basicmanagedprofile
      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.example.android.basicmanagedprofile;
     18 
     19 import android.app.Activity;
     20 import android.app.AlertDialog;
     21 import android.app.Fragment;
     22 import android.app.admin.DevicePolicyManager;
     23 import android.content.ActivityNotFoundException;
     24 import android.content.Context;
     25 import android.content.DialogInterface;
     26 import android.content.Intent;
     27 import android.content.IntentFilter;
     28 import android.content.pm.ApplicationInfo;
     29 import android.content.pm.PackageManager;
     30 import android.os.Bundle;
     31 import android.util.Log;
     32 import android.view.LayoutInflater;
     33 import android.view.View;
     34 import android.view.ViewGroup;
     35 import android.widget.Button;
     36 import android.widget.CompoundButton;
     37 import android.widget.ScrollView;
     38 import android.widget.Switch;
     39 import android.widget.TextView;
     40 import android.widget.Toast;
     41 
     42 import static android.app.admin.DevicePolicyManager.FLAG_MANAGED_CAN_ACCESS_PARENT;
     43 import static android.app.admin.DevicePolicyManager.FLAG_PARENT_CAN_ACCESS_MANAGED;
     44 
     45 /**
     46  * Provides several functions that are available in a managed profile. This includes
     47  * enabling/disabling other apps, setting app restrictions, enabling/disabling intent forwarding,
     48  * and wiping out all the data in the profile.
     49  */
     50 public class BasicManagedProfileFragment extends Fragment
     51         implements View.OnClickListener,
     52         CompoundButton.OnCheckedChangeListener {
     53 
     54     /**
     55      * Tag for logging.
     56      */
     57     private static final String TAG = "BasicManagedProfileFragment";
     58 
     59     /**
     60      * Package name of calculator
     61      */
     62     private static final String PACKAGE_NAME_CALCULATOR = "com.android.calculator2";
     63 
     64     /**
     65      * Package name of Chrome
     66      */
     67     private static final String PACKAGE_NAME_CHROME = "com.android.chrome";
     68 
     69     /**
     70      * {@link Button} to remove this managed profile.
     71      */
     72     private Button mButtonRemoveProfile;
     73 
     74     /**
     75      * Whether the calculator app is enabled in this profile
     76      */
     77     private boolean mCalculatorEnabled;
     78 
     79     /**
     80      * Whether Chrome is enabled in this profile
     81      */
     82     private boolean mChromeEnabled;
     83 
     84     public BasicManagedProfileFragment() {
     85     }
     86 
     87     public static BasicManagedProfileFragment newInstance() {
     88         return new BasicManagedProfileFragment();
     89     }
     90 
     91     @Override
     92     public View onCreateView(LayoutInflater inflater, ViewGroup container,
     93                              Bundle savedInstanceState) {
     94         return inflater.inflate(R.layout.fragment_main, container, false);
     95     }
     96 
     97     @Override
     98     public void onAttach(Activity activity) {
     99         super.onAttach(activity);
    100         // Retrieves whether the calculator app is enabled in this profile
    101         mCalculatorEnabled = isApplicationEnabled(PACKAGE_NAME_CALCULATOR);
    102         // Retrieves whether Chrome is enabled in this profile
    103         mChromeEnabled = isApplicationEnabled(PACKAGE_NAME_CHROME);
    104     }
    105 
    106     /**
    107      * Checks if the application is available in this profile.
    108      *
    109      * @param packageName The package name
    110      * @return True if the application is available in this profile.
    111      */
    112     private boolean isApplicationEnabled(String packageName) {
    113         Activity activity = getActivity();
    114         PackageManager packageManager = activity.getPackageManager();
    115         try {
    116             ApplicationInfo applicationInfo = packageManager.getApplicationInfo(
    117                     packageName, PackageManager.GET_UNINSTALLED_PACKAGES);
    118             // Return false if the app is not installed in this profile
    119             if (0 == (applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED)) {
    120                 return false;
    121             }
    122             // Check if the app is not hidden in this profile
    123             DevicePolicyManager devicePolicyManager =
    124                     (DevicePolicyManager) activity.getSystemService(Activity.DEVICE_POLICY_SERVICE);
    125             return !devicePolicyManager.isApplicationHidden(
    126                     BasicDeviceAdminReceiver.getComponentName(activity), packageName);
    127         } catch (PackageManager.NameNotFoundException e) {
    128             return false;
    129         }
    130     }
    131 
    132     @Override
    133     public void onViewCreated(View view, Bundle savedInstanceState) {
    134         // Bind event listeners and initial states
    135         view.findViewById(R.id.set_chrome_restrictions).setOnClickListener(this);
    136         view.findViewById(R.id.clear_chrome_restrictions).setOnClickListener(this);
    137         view.findViewById(R.id.enable_forwarding).setOnClickListener(this);
    138         view.findViewById(R.id.disable_forwarding).setOnClickListener(this);
    139         view.findViewById(R.id.send_intent).setOnClickListener(this);
    140         mButtonRemoveProfile = (Button) view.findViewById(R.id.remove_profile);
    141         mButtonRemoveProfile.setOnClickListener(this);
    142         Switch toggleCalculator = (Switch) view.findViewById(R.id.toggle_calculator);
    143         toggleCalculator.setChecked(mCalculatorEnabled);
    144         toggleCalculator.setOnCheckedChangeListener(this);
    145         Switch toggleChrome = (Switch) view.findViewById(R.id.toggle_chrome);
    146         toggleChrome.setChecked(mChromeEnabled);
    147         toggleChrome.setOnCheckedChangeListener(this);
    148     }
    149 
    150     @Override
    151     public void onClick(View view) {
    152         switch (view.getId()) {
    153             case R.id.set_chrome_restrictions: {
    154                 setChromeRestrictions();
    155                 break;
    156             }
    157             case R.id.clear_chrome_restrictions: {
    158                 clearChromeRestrictions();
    159                 break;
    160             }
    161             case R.id.enable_forwarding: {
    162                 enableForwarding();
    163                 break;
    164             }
    165             case R.id.disable_forwarding: {
    166                 disableForwarding();
    167                 break;
    168             }
    169             case R.id.send_intent: {
    170                 sendIntent();
    171                 break;
    172             }
    173             case R.id.remove_profile: {
    174                 mButtonRemoveProfile.setEnabled(false);
    175                 removeProfile();
    176                 break;
    177             }
    178         }
    179     }
    180 
    181     @Override
    182     public void onCheckedChanged(CompoundButton compoundButton, boolean checked) {
    183         switch (compoundButton.getId()) {
    184             case R.id.toggle_calculator: {
    185                 setAppEnabled(PACKAGE_NAME_CALCULATOR, checked);
    186                 mCalculatorEnabled = checked;
    187                 break;
    188             }
    189             case R.id.toggle_chrome: {
    190                 setAppEnabled(PACKAGE_NAME_CHROME, checked);
    191                 mChromeEnabled = checked;
    192                 break;
    193             }
    194         }
    195     }
    196 
    197     /**
    198      * Enables or disables the specified app in this profile.
    199      *
    200      * @param packageName The package name of the target app.
    201      * @param enabled     Pass true to enable the app.
    202      */
    203     private void setAppEnabled(String packageName, boolean enabled) {
    204         Activity activity = getActivity();
    205         if (null == activity) {
    206             return;
    207         }
    208         PackageManager packageManager = activity.getPackageManager();
    209         DevicePolicyManager devicePolicyManager =
    210                 (DevicePolicyManager) activity.getSystemService(Context.DEVICE_POLICY_SERVICE);
    211         try {
    212             ApplicationInfo applicationInfo = packageManager.getApplicationInfo(packageName,
    213                     PackageManager.GET_UNINSTALLED_PACKAGES);
    214             // Here, we check the ApplicationInfo of the target app, and see if the flags have
    215             // ApplicationInfo.FLAG_INSTALLED turned on using bitwise operation.
    216             if (0 == (applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED)) {
    217                 // If the app is not installed in this profile, we can enable it by
    218                 // DPM.enableSystemApp
    219                 if (enabled) {
    220                     devicePolicyManager.enableSystemApp(
    221                             BasicDeviceAdminReceiver.getComponentName(activity), packageName);
    222                 } else {
    223                     // But we cannot disable the app since it is already disabled
    224                     Log.e(TAG, "Cannot disable this app: " + packageName);
    225                     return;
    226                 }
    227             } else {
    228                 // If the app is already installed, we can enable or disable it by
    229                 // DPM.setApplicationHidden
    230                 devicePolicyManager.setApplicationHidden(
    231                         BasicDeviceAdminReceiver.getComponentName(activity), packageName, !enabled);
    232             }
    233             Toast.makeText(activity, enabled ? R.string.enabled : R.string.disabled,
    234                     Toast.LENGTH_SHORT).show();
    235         } catch (PackageManager.NameNotFoundException e) {
    236             Log.e(TAG, "The app cannot be found: " + packageName, e);
    237         }
    238     }
    239 
    240     /**
    241      * Sets restrictions to Chrome
    242      */
    243     private void setChromeRestrictions() {
    244         final Activity activity = getActivity();
    245         if (null == activity) {
    246             return;
    247         }
    248         final DevicePolicyManager manager =
    249             (DevicePolicyManager) activity.getSystemService(Context.DEVICE_POLICY_SERVICE);
    250         final Bundle settings = new Bundle();
    251         settings.putString("EditBookmarksEnabled", "false");
    252         settings.putString("IncognitoModeAvailability", "1");
    253         settings.putString("ManagedBookmarks",
    254                            "[{\"name\": \"Chromium\", \"url\": \"http://chromium.org\"}, " +
    255                            "{\"name\": \"Google\", \"url\": \"https://www.google.com\"}]");
    256         settings.putString("DefaultSearchProviderEnabled", "true");
    257         settings.putString("DefaultSearchProviderName", "\"LMGTFY\"");
    258         settings.putString("DefaultSearchProviderSearchURL",
    259                 "\"http://lmgtfy.com/?q={searchTerms}\"");
    260         settings.putString("URLBlacklist", "[\"example.com\", \"example.org\"]");
    261         StringBuilder message = new StringBuilder("Setting Chrome restrictions:");
    262         for (String key : settings.keySet()) {
    263             message.append("\n");
    264             message.append(key);
    265             message.append(": ");
    266             message.append(settings.getString(key));
    267         }
    268         ScrollView view = new ScrollView(activity);
    269         TextView text = new TextView(activity);
    270         text.setText(message);
    271         int size = (int) activity.getResources().getDimension(R.dimen.activity_horizontal_margin);
    272         view.setPadding(size, size, size, size);
    273         view.addView(text);
    274         new AlertDialog.Builder(activity)
    275                 .setView(view)
    276                 .setNegativeButton(android.R.string.cancel, null)
    277                 .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
    278                     @Override
    279                     public void onClick(DialogInterface dialogInterface, int i) {
    280                         // This is how you can set restrictions to an app.
    281                         // The format for settings in Bundle differs from app to app.
    282                         manager.setApplicationRestrictions
    283                                 (BasicDeviceAdminReceiver.getComponentName(activity),
    284                                         PACKAGE_NAME_CHROME, settings);
    285                         Toast.makeText(activity, R.string.restrictions_set,
    286                                 Toast.LENGTH_SHORT).show();
    287                     }
    288                 })
    289                 .show();
    290     }
    291 
    292     /**
    293      * Clears restrictions to Chrome
    294      */
    295     private void clearChromeRestrictions() {
    296         final Activity activity = getActivity();
    297         if (null == activity) {
    298             return;
    299         }
    300         final DevicePolicyManager manager =
    301                 (DevicePolicyManager) activity.getSystemService(Context.DEVICE_POLICY_SERVICE);
    302         // In order to clear restrictions, pass null as the restriction Bundle for
    303         // setApplicationRestrictions
    304         manager.setApplicationRestrictions
    305                 (BasicDeviceAdminReceiver.getComponentName(activity),
    306                         PACKAGE_NAME_CHROME, null);
    307         Toast.makeText(activity, R.string.cleared, Toast.LENGTH_SHORT).show();
    308     }
    309 
    310     /**
    311      * Enables forwarding of share intent between private account and managed profile.
    312      */
    313     private void enableForwarding() {
    314         Activity activity = getActivity();
    315         if (null == activity || activity.isFinishing()) {
    316             return;
    317         }
    318         DevicePolicyManager manager =
    319                 (DevicePolicyManager) activity.getSystemService(Context.DEVICE_POLICY_SERVICE);
    320         try {
    321             IntentFilter filter = new IntentFilter(Intent.ACTION_SEND);
    322             filter.addDataType("text/plain");
    323             filter.addDataType("image/jpeg");
    324             // This is how you can register an IntentFilter as allowed pattern of Intent forwarding
    325             manager.addCrossProfileIntentFilter(BasicDeviceAdminReceiver.getComponentName(activity),
    326                     filter, FLAG_MANAGED_CAN_ACCESS_PARENT | FLAG_PARENT_CAN_ACCESS_MANAGED);
    327         } catch (IntentFilter.MalformedMimeTypeException e) {
    328             e.printStackTrace();
    329         }
    330     }
    331 
    332     /**
    333      * Disables forwarding of all intents.
    334      */
    335     private void disableForwarding() {
    336         Activity activity = getActivity();
    337         if (null == activity || activity.isFinishing()) {
    338             return;
    339         }
    340         DevicePolicyManager manager =
    341                 (DevicePolicyManager) activity.getSystemService(Context.DEVICE_POLICY_SERVICE);
    342         manager.clearCrossProfileIntentFilters(BasicDeviceAdminReceiver.getComponentName(activity));
    343     }
    344 
    345     /**
    346      * Sends a sample intent of a plain text message.  This is just a utility function to see how
    347      * the intent forwarding works.
    348      */
    349     private void sendIntent() {
    350         Activity activity = getActivity();
    351         if (null == activity || activity.isFinishing()) {
    352             return;
    353         }
    354         DevicePolicyManager manager =
    355                 (DevicePolicyManager) activity.getSystemService(Context.DEVICE_POLICY_SERVICE);
    356         Intent intent = new Intent(Intent.ACTION_SEND);
    357         intent.setType("text/plain");
    358         intent.putExtra(Intent.EXTRA_TEXT,
    359                 manager.isProfileOwnerApp(activity.getApplicationContext().getPackageName())
    360                         ? "From the managed account" : "From the primary account");
    361         try {
    362             startActivity(intent);
    363             Log.d(TAG, "A sample intent was sent.");
    364         } catch (ActivityNotFoundException e) {
    365             Toast.makeText(activity, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
    366         }
    367     }
    368 
    369     /**
    370      * Wipes out all the data related to this managed profile.
    371      */
    372     private void removeProfile() {
    373         Activity activity = getActivity();
    374         if (null == activity || activity.isFinishing()) {
    375             return;
    376         }
    377         DevicePolicyManager manager =
    378                 (DevicePolicyManager) activity.getSystemService(Context.DEVICE_POLICY_SERVICE);
    379         manager.wipeData(0);
    380         // The screen turns off here
    381     }
    382 
    383 }
    384