Home | History | Annotate | Download | only in deviceowner
      1 /*
      2  * Copyright (C) 2015 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.deviceowner;
     18 
     19 import android.app.Activity;
     20 import android.app.admin.DevicePolicyManager;
     21 import android.content.ComponentName;
     22 import android.content.ContentResolver;
     23 import android.content.Context;
     24 import android.content.Intent;
     25 import android.content.IntentFilter;
     26 import android.content.SharedPreferences;
     27 import android.content.pm.ResolveInfo;
     28 import android.os.Bundle;
     29 import android.provider.Settings;
     30 import android.support.annotation.Nullable;
     31 import android.support.v4.app.Fragment;
     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.SimpleAdapter;
     38 import android.widget.Spinner;
     39 import android.widget.Switch;
     40 
     41 import java.util.ArrayList;
     42 import java.util.HashMap;
     43 import java.util.List;
     44 
     45 /**
     46  * Demonstrates the usage of the most common device management APIs for the device owner case.
     47  * In addition to various features available for profile owners, device owners can perform extra
     48  * actions, such as configuring global settings and enforcing a preferred Activity for a specific
     49  * IntentFilter.
     50  */
     51 public class DeviceOwnerFragment extends Fragment {
     52 
     53     // Keys for SharedPreferences
     54     private static final String PREFS_DEVICE_OWNER = "DeviceOwnerFragment";
     55     private static final String PREF_LAUNCHER = "launcher";
     56 
     57     private DevicePolicyManager mDevicePolicyManager;
     58 
     59     // View references
     60     private Switch mSwitchAutoTime;
     61     private Switch mSwitchAutoTimeZone;
     62     private Spinner mAvailableLaunchers;
     63     private Button mButtonLauncher;
     64 
     65     // Adapter for the spinner to show list of available launchers
     66     private LauncherAdapter mAdapter;
     67 
     68     /**
     69      * Handles events on the Switches.
     70      */
     71     private Switch.OnCheckedChangeListener mOnCheckedChangeListener
     72             = new Switch.OnCheckedChangeListener() {
     73 
     74         @Override
     75         public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
     76             switch (buttonView.getId()) {
     77                 case R.id.switch_auto_time:
     78                     setBooleanGlobalSetting(Settings.Global.AUTO_TIME, isChecked);
     79                     retrieveCurrentSettings(getActivity());
     80                     break;
     81                 case R.id.switch_auto_time_zone:
     82                     setBooleanGlobalSetting(Settings.Global.AUTO_TIME_ZONE, isChecked);
     83                     retrieveCurrentSettings(getActivity());
     84                     break;
     85             }
     86         }
     87 
     88     };
     89 
     90     /**
     91      * Handles click events on the Button.
     92      */
     93     private View.OnClickListener mOnClickListener
     94             = new View.OnClickListener() {
     95 
     96         @Override
     97         public void onClick(View v) {
     98             switch (v.getId()) {
     99                 case R.id.set_preferred_launcher:
    100                     if (loadPersistentPreferredLauncher(getActivity()) == null) {
    101                         setPreferredLauncher();
    102                     } else {
    103                         clearPreferredLauncher();
    104                     }
    105                     retrieveCurrentSettings(getActivity());
    106                     break;
    107             }
    108         }
    109 
    110     };
    111 
    112     /**
    113      * @return A newly instantiated {@link DeviceOwnerFragment}.
    114      */
    115     public static DeviceOwnerFragment newInstance() {
    116         return new DeviceOwnerFragment();
    117     }
    118 
    119     @Nullable
    120     @Override
    121     public View onCreateView(LayoutInflater inflater, ViewGroup container,
    122                              Bundle savedInstanceState) {
    123         return inflater.inflate(R.layout.fragment_device_owner, container, false);
    124     }
    125 
    126     @Override
    127     public void onViewCreated(View view, Bundle savedInstanceState) {
    128         // Retain references
    129         mSwitchAutoTime = (Switch) view.findViewById(R.id.switch_auto_time);
    130         mSwitchAutoTimeZone = (Switch) view.findViewById(R.id.switch_auto_time_zone);
    131         mAvailableLaunchers = (Spinner) view.findViewById(R.id.available_launchers);
    132         mButtonLauncher = (Button) view.findViewById(R.id.set_preferred_launcher);
    133         // Bind event handlers
    134         mSwitchAutoTime.setOnCheckedChangeListener(mOnCheckedChangeListener);
    135         mSwitchAutoTimeZone.setOnCheckedChangeListener(mOnCheckedChangeListener);
    136         mButtonLauncher.setOnClickListener(mOnClickListener);
    137     }
    138 
    139     @Override
    140     public void onAttach(Context context) {
    141         super.onAttach(context);
    142         mDevicePolicyManager =
    143                 (DevicePolicyManager) context.getSystemService(Activity.DEVICE_POLICY_SERVICE);
    144     }
    145 
    146     @Override
    147     public void onDetach() {
    148         mDevicePolicyManager = null;
    149         super.onDetach();
    150     }
    151 
    152     @Override
    153     public void onResume() {
    154         super.onResume();
    155         Activity activity = getActivity();
    156         if (activity != null) {
    157             retrieveCurrentSettings(activity);
    158         }
    159     }
    160 
    161     /**
    162      * Retrieves the current global settings and changes the UI accordingly.
    163      *
    164      * @param activity The activity
    165      */
    166     private void retrieveCurrentSettings(Activity activity) {
    167         // Global settings
    168         setCheckedSafely(mSwitchAutoTime,
    169                 getBooleanGlobalSetting(activity.getContentResolver(), Settings.Global.AUTO_TIME));
    170         setCheckedSafely(mSwitchAutoTimeZone,
    171                 getBooleanGlobalSetting(activity.getContentResolver(),
    172                         Settings.Global.AUTO_TIME_ZONE));
    173 
    174         // Launcher
    175         Intent intent = new Intent(Intent.ACTION_MAIN);
    176         intent.addCategory(Intent.CATEGORY_HOME);
    177         List<ResolveInfo> list = activity.getPackageManager()
    178                 .queryIntentActivities(intent, /* default flags */ 0);
    179         mAdapter = new LauncherAdapter(activity, list);
    180         mAvailableLaunchers.setAdapter(mAdapter);
    181         String packageName = loadPersistentPreferredLauncher(activity);
    182         if (packageName == null) { // No preferred launcher is set
    183             mAvailableLaunchers.setEnabled(true);
    184             mButtonLauncher.setText(R.string.set_as_preferred);
    185         } else {
    186             int position = -1;
    187             for (int i = 0; i < list.size(); ++i) {
    188                 if (list.get(i).activityInfo.packageName.equals(packageName)) {
    189                     position = i;
    190                     break;
    191                 }
    192             }
    193             if (position != -1) {
    194                 mAvailableLaunchers.setSelection(position);
    195                 mAvailableLaunchers.setEnabled(false);
    196                 mButtonLauncher.setText(R.string.clear_preferred);
    197             }
    198         }
    199     }
    200 
    201     /**
    202      * Retrieves the current boolean value of the specified global setting.
    203      *
    204      * @param resolver The ContentResolver
    205      * @param setting  The setting to be retrieved
    206      * @return The current boolean value
    207      */
    208     private static boolean getBooleanGlobalSetting(ContentResolver resolver, String setting) {
    209         return 0 != Settings.Global.getInt(resolver, setting, 0);
    210     }
    211 
    212     /**
    213      * Sets the boolean value of the specified global setting.
    214      *
    215      * @param setting The setting to be set
    216      * @param value   The value to be set
    217      */
    218     private void setBooleanGlobalSetting(String setting, boolean value) {
    219         mDevicePolicyManager.setGlobalSetting(
    220                 // The ComponentName of the device owner
    221                 DeviceOwnerReceiver.getComponentName(getActivity()),
    222                 // The settings to be set
    223                 setting,
    224                 // The value we write here is a string representation for SQLite
    225                 value ? "1" : "0");
    226     }
    227 
    228     /**
    229      * A utility method to set the checked state of the button without invoking its listener.
    230      *
    231      * @param button  The button
    232      * @param checked The value to be set
    233      */
    234     private void setCheckedSafely(CompoundButton button, boolean checked) {
    235         button.setOnCheckedChangeListener(null);
    236         button.setChecked(checked);
    237         button.setOnCheckedChangeListener(mOnCheckedChangeListener);
    238     }
    239 
    240     /**
    241      * Loads the package name from SharedPreferences.
    242      *
    243      * @param activity The activity
    244      * @return The package name of the launcher currently set as preferred, or null if there is no
    245      * preferred launcher.
    246      */
    247     private static String loadPersistentPreferredLauncher(Activity activity) {
    248         return activity.getSharedPreferences(PREFS_DEVICE_OWNER, Context.MODE_PRIVATE)
    249                 .getString(PREF_LAUNCHER, null);
    250     }
    251 
    252     /**
    253      * Saves the package name into SharedPreferences.
    254      *
    255      * @param activity    The activity
    256      * @param packageName The package name to be saved. Pass null to remove the preferred launcher.
    257      */
    258     private static void savePersistentPreferredLauncher(Activity activity, String packageName) {
    259         SharedPreferences.Editor editor = activity.getSharedPreferences(PREFS_DEVICE_OWNER,
    260                 Context.MODE_PRIVATE).edit();
    261         if (packageName == null) {
    262             editor.remove(PREF_LAUNCHER);
    263         } else {
    264             editor.putString(PREF_LAUNCHER, packageName);
    265         }
    266         editor.apply();
    267     }
    268 
    269     /**
    270      * Sets the selected launcher as preferred.
    271      */
    272     private void setPreferredLauncher() {
    273         Activity activity = getActivity();
    274         if (activity == null) {
    275             return;
    276         }
    277         IntentFilter filter = new IntentFilter(Intent.ACTION_MAIN);
    278         filter.addCategory(Intent.CATEGORY_HOME);
    279         filter.addCategory(Intent.CATEGORY_DEFAULT);
    280         ComponentName componentName = mAdapter.getComponentName(
    281                 mAvailableLaunchers.getSelectedItemPosition());
    282         mDevicePolicyManager.addPersistentPreferredActivity(
    283                 DeviceOwnerReceiver.getComponentName(activity), filter, componentName);
    284         savePersistentPreferredLauncher(activity, componentName.getPackageName());
    285     }
    286 
    287     /**
    288      * Clears the launcher currently set as preferred.
    289      */
    290     private void clearPreferredLauncher() {
    291         Activity activity = getActivity();
    292         if (activity == null) {
    293             return;
    294         }
    295         mDevicePolicyManager.clearPackagePersistentPreferredActivities(
    296                 DeviceOwnerReceiver.getComponentName(activity),
    297                 loadPersistentPreferredLauncher(activity));
    298         savePersistentPreferredLauncher(activity, null);
    299     }
    300 
    301     /**
    302      * Shows list of {@link ResolveInfo} in a {@link Spinner}.
    303      */
    304     private static class LauncherAdapter extends SimpleAdapter {
    305 
    306         private static final String KEY_PACKAGE_NAME = "package_name";
    307         private static final String KEY_ACTIVITY_NAME = "activity_name";
    308 
    309         public LauncherAdapter(Context context, List<ResolveInfo> list) {
    310             super(context, createData(list), android.R.layout.simple_list_item_1,
    311                     new String[]{KEY_PACKAGE_NAME},
    312                     new int[]{android.R.id.text1});
    313         }
    314 
    315         private static List<HashMap<String, String>> createData(List<ResolveInfo> list) {
    316             List<HashMap<String, String>> data = new ArrayList<>();
    317             for (ResolveInfo info : list) {
    318                 HashMap<String, String> map = new HashMap<>();
    319                 map.put(KEY_PACKAGE_NAME, info.activityInfo.packageName);
    320                 map.put(KEY_ACTIVITY_NAME, info.activityInfo.name);
    321                 data.add(map);
    322             }
    323             return data;
    324         }
    325 
    326         public ComponentName getComponentName(int position) {
    327             @SuppressWarnings("unchecked")
    328             HashMap<String, String> map = (HashMap<String, String>) getItem(position);
    329             return new ComponentName(map.get(KEY_PACKAGE_NAME), map.get(KEY_ACTIVITY_NAME));
    330         }
    331 
    332     }
    333 
    334 }
    335