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.Fragment; 21 import android.app.admin.DevicePolicyManager; 22 import android.content.ComponentName; 23 import android.content.ContentResolver; 24 import android.content.Context; 25 import android.content.Intent; 26 import android.content.IntentFilter; 27 import android.content.SharedPreferences; 28 import android.content.pm.ResolveInfo; 29 import android.os.Bundle; 30 import android.provider.Settings; 31 import android.support.annotation.Nullable; 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 */ newInstance()115 public static DeviceOwnerFragment newInstance() { 116 return new DeviceOwnerFragment(); 117 } 118 119 @Nullable 120 @Override onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)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 onViewCreated(View view, Bundle savedInstanceState)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 onAttach(Activity activity)140 public void onAttach(Activity activity) { 141 super.onAttach(activity); 142 mDevicePolicyManager = 143 (DevicePolicyManager) activity.getSystemService(Activity.DEVICE_POLICY_SERVICE); 144 } 145 146 @Override onDetach()147 public void onDetach() { 148 mDevicePolicyManager = null; 149 super.onDetach(); 150 } 151 152 @Override onResume()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 */ retrieveCurrentSettings(Activity activity)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 */ getBooleanGlobalSetting(ContentResolver resolver, String setting)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 */ setBooleanGlobalSetting(String setting, boolean value)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 */ setCheckedSafely(CompoundButton button, boolean checked)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 */ loadPersistentPreferredLauncher(Activity activity)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 */ savePersistentPreferredLauncher(Activity activity, String packageName)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 */ setPreferredLauncher()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 */ clearPreferredLauncher()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 LauncherAdapter(Context context, List<ResolveInfo> list)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 createData(List<ResolveInfo> list)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 getComponentName(int position)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