├── .google └── packaging.yaml ├── Application ├── build.gradle └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── example │ │ └── android │ │ └── basicmanagedprofile │ │ ├── BasicDeviceAdminReceiver.java │ │ ├── BasicManagedProfileFragment.java │ │ ├── EnableProfileActivity.java │ │ ├── MainActivity.java │ │ └── SetupProfileFragment.java │ └── res │ ├── drawable-hdpi │ └── tile.9.png │ ├── drawable-xxhdpi │ └── badge.png │ ├── drawable │ └── ic_launcher_badged.xml │ ├── layout │ ├── activity_main_real.xml │ ├── activity_setup.xml │ ├── fragment_main.xml │ └── fragment_setup_profile.xml │ ├── mipmap-hdpi │ └── ic_launcher.png │ ├── mipmap-mdpi │ └── ic_launcher.png │ ├── mipmap-xhdpi │ └── ic_launcher.png │ ├── mipmap-xxhdpi │ └── ic_launcher.png │ ├── mipmap-xxxhdpi │ └── ic_launcher.png │ ├── values-sw600dp │ ├── template-dimens.xml │ └── template-styles.xml │ ├── values-v11 │ └── template-styles.xml │ ├── values-v21 │ ├── base-colors.xml │ └── base-template-styles.xml │ ├── values-w820dp │ └── dimens.xml │ ├── values │ ├── base-strings.xml │ ├── dimens.xml │ ├── strings.xml │ ├── styles.xml │ ├── template-dimens.xml │ └── template-styles.xml │ └── xml │ └── basic_device_admin_receiver.xml ├── CONTRIB.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── build.gradle ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── packaging.yaml ├── screenshots ├── icon-web.png ├── main.png ├── not_set_up.png └── set_up.png └── settings.gradle /.google/packaging.yaml: -------------------------------------------------------------------------------- 1 | 2 | # GOOGLE SAMPLE PACKAGING DATA 3 | # 4 | # This file is used by Google as part of our samples packaging process. 5 | # End users may safely ignore this file. It has no relevance to other systems. 6 | --- 7 | status: PUBLISHED 8 | technologies: [Android] 9 | categories: [Device Admin] 10 | languages: [Java] 11 | solutions: [Mobile] 12 | github: android-BasicManagedProfile 13 | level: ADVANCED 14 | icon: screenshots/icon-web.png 15 | apiRefs: 16 | - android:android.app.admin.DevicePolicyManager 17 | - android:android.app.admin.DeviceAdminReceiver 18 | license: apache2 19 | -------------------------------------------------------------------------------- /Application/build.gradle: -------------------------------------------------------------------------------- 1 | 2 | buildscript { 3 | repositories { 4 | jcenter() 5 | google() 6 | } 7 | 8 | dependencies { 9 | classpath 'com.android.tools.build:gradle:3.0.1' 10 | } 11 | } 12 | 13 | apply plugin: 'com.android.application' 14 | 15 | repositories { 16 | jcenter() 17 | google() 18 | } 19 | 20 | dependencies { 21 | compile "com.android.support:support-v4:27.0.2" 22 | compile "com.android.support:support-v13:27.0.2" 23 | compile "com.android.support:cardview-v7:27.0.2" 24 | compile "com.android.support:appcompat-v7:27.0.2" 25 | } 26 | 27 | // The sample build uses multiple directories to 28 | // keep boilerplate and common code separate from 29 | // the main sample code. 30 | List dirs = [ 31 | 'main', // main sample code; look here for the interesting stuff. 32 | 'common', // components that are reused by multiple samples 33 | 'template'] // boilerplate code that is generated by the sample template process 34 | 35 | android { 36 | compileSdkVersion 27 37 | 38 | buildToolsVersion "27.0.2" 39 | 40 | defaultConfig { 41 | minSdkVersion 21 42 | targetSdkVersion 27 43 | } 44 | 45 | compileOptions { 46 | sourceCompatibility JavaVersion.VERSION_1_7 47 | targetCompatibility JavaVersion.VERSION_1_7 48 | } 49 | 50 | sourceSets { 51 | main { 52 | dirs.each { dir -> 53 | java.srcDirs "src/${dir}/java" 54 | res.srcDirs "src/${dir}/res" 55 | } 56 | } 57 | androidTest.setRoot('tests') 58 | androidTest.java.srcDirs = ['tests/src'] 59 | 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /Application/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 24 | 25 | 31 | 32 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 44 | 45 | 50 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /Application/src/main/java/com/example/android/basicmanagedprofile/BasicDeviceAdminReceiver.java: -------------------------------------------------------------------------------- 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.admin.DeviceAdminReceiver; 20 | import android.content.ComponentName; 21 | import android.content.Context; 22 | import android.content.Intent; 23 | 24 | /** 25 | * Handles events related to managed profile. 26 | */ 27 | public class BasicDeviceAdminReceiver extends DeviceAdminReceiver { 28 | 29 | /** 30 | * Called on the new profile when managed profile provisioning has completed. Managed profile 31 | * provisioning is the process of setting up the device so that it has a separate profile which 32 | * is managed by the mobile device management(mdm) application that triggered the provisioning. 33 | * Note that the managed profile is not fully visible until it is enabled. 34 | */ 35 | @Override 36 | public void onProfileProvisioningComplete(Context context, Intent intent) { 37 | // EnableProfileActivity is launched with the newly set up profile. 38 | Intent launch = new Intent(context, EnableProfileActivity.class); 39 | launch.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 40 | context.startActivity(launch); 41 | } 42 | 43 | /** 44 | * Generates a {@link ComponentName} that is used throughout the app. 45 | * @return a {@link ComponentName} 46 | */ 47 | public static ComponentName getComponentName(Context context) { 48 | return new ComponentName(context.getApplicationContext(), BasicDeviceAdminReceiver.class); 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /Application/src/main/java/com/example/android/basicmanagedprofile/BasicManagedProfileFragment.java: -------------------------------------------------------------------------------- 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.Build; 31 | import android.os.Bundle; 32 | import android.util.Log; 33 | import android.view.LayoutInflater; 34 | import android.view.View; 35 | import android.view.ViewGroup; 36 | import android.widget.Button; 37 | import android.widget.CompoundButton; 38 | import android.widget.ScrollView; 39 | import android.widget.Switch; 40 | import android.widget.TextView; 41 | import android.widget.Toast; 42 | 43 | import static android.app.admin.DevicePolicyManager.FLAG_MANAGED_CAN_ACCESS_PARENT; 44 | import static android.app.admin.DevicePolicyManager.FLAG_PARENT_CAN_ACCESS_MANAGED; 45 | 46 | /** 47 | * Provides several functions that are available in a managed profile. This includes 48 | * enabling/disabling other apps, setting app restrictions, enabling/disabling intent forwarding, 49 | * and wiping out all the data in the profile. 50 | */ 51 | public class BasicManagedProfileFragment extends Fragment 52 | implements View.OnClickListener, 53 | CompoundButton.OnCheckedChangeListener { 54 | 55 | /** 56 | * Tag for logging. 57 | */ 58 | private static final String TAG = "ManagedProfileFragment"; 59 | 60 | /** 61 | * Package name of calculator 62 | */ 63 | private static final String PACKAGE_NAME_CALCULATOR = "com.android.calculator2"; 64 | 65 | /** 66 | * Package name of Chrome 67 | */ 68 | private static final String PACKAGE_NAME_CHROME = "com.android.chrome"; 69 | 70 | /** 71 | * {@link Button} to remove this managed profile. 72 | */ 73 | private Button mButtonRemoveProfile; 74 | 75 | /** 76 | * Whether the calculator app is enabled in this profile 77 | */ 78 | private boolean mCalculatorEnabled; 79 | 80 | /** 81 | * Whether Chrome is enabled in this profile 82 | */ 83 | private boolean mChromeEnabled; 84 | 85 | public BasicManagedProfileFragment() { 86 | } 87 | 88 | public static BasicManagedProfileFragment newInstance() { 89 | return new BasicManagedProfileFragment(); 90 | } 91 | 92 | @Override 93 | public View onCreateView(LayoutInflater inflater, ViewGroup container, 94 | Bundle savedInstanceState) { 95 | return inflater.inflate(R.layout.fragment_main, container, false); 96 | } 97 | 98 | @Override 99 | public void onAttach(Context context) { 100 | super.onAttach(context); 101 | // Retrieves whether the calculator app is enabled in this profile 102 | mCalculatorEnabled = isApplicationEnabled(PACKAGE_NAME_CALCULATOR); 103 | // Retrieves whether Chrome is enabled in this profile 104 | mChromeEnabled = isApplicationEnabled(PACKAGE_NAME_CHROME); 105 | } 106 | 107 | /** 108 | * Checks if the application is available in this profile. 109 | * 110 | * @param packageName The package name 111 | * @return True if the application is available in this profile. 112 | */ 113 | private boolean isApplicationEnabled(String packageName) { 114 | Activity activity = getActivity(); 115 | PackageManager packageManager = activity.getPackageManager(); 116 | try { 117 | int packageFlags; 118 | if(Build.VERSION.SDK_INT < 24){ 119 | //noinspection deprecation 120 | packageFlags = PackageManager.GET_UNINSTALLED_PACKAGES; 121 | }else{ 122 | packageFlags = PackageManager.MATCH_UNINSTALLED_PACKAGES; 123 | } 124 | ApplicationInfo applicationInfo = packageManager.getApplicationInfo( 125 | packageName, packageFlags); 126 | // Return false if the app is not installed in this profile 127 | if (0 == (applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED)) { 128 | return false; 129 | } 130 | // Check if the app is not hidden in this profile 131 | DevicePolicyManager devicePolicyManager = 132 | (DevicePolicyManager) activity.getSystemService(Activity.DEVICE_POLICY_SERVICE); 133 | return !devicePolicyManager.isApplicationHidden( 134 | BasicDeviceAdminReceiver.getComponentName(activity), packageName); 135 | } catch (PackageManager.NameNotFoundException e) { 136 | return false; 137 | } 138 | } 139 | 140 | @Override 141 | public void onViewCreated(View view, Bundle savedInstanceState) { 142 | // Bind event listeners and initial states 143 | view.findViewById(R.id.set_chrome_restrictions).setOnClickListener(this); 144 | view.findViewById(R.id.clear_chrome_restrictions).setOnClickListener(this); 145 | view.findViewById(R.id.enable_forwarding).setOnClickListener(this); 146 | view.findViewById(R.id.disable_forwarding).setOnClickListener(this); 147 | view.findViewById(R.id.send_intent).setOnClickListener(this); 148 | mButtonRemoveProfile = (Button) view.findViewById(R.id.remove_profile); 149 | mButtonRemoveProfile.setOnClickListener(this); 150 | Switch toggleCalculator = (Switch) view.findViewById(R.id.toggle_calculator); 151 | toggleCalculator.setChecked(mCalculatorEnabled); 152 | toggleCalculator.setOnCheckedChangeListener(this); 153 | Switch toggleChrome = (Switch) view.findViewById(R.id.toggle_chrome); 154 | toggleChrome.setChecked(mChromeEnabled); 155 | toggleChrome.setOnCheckedChangeListener(this); 156 | } 157 | 158 | @Override 159 | public void onClick(View view) { 160 | switch (view.getId()) { 161 | case R.id.set_chrome_restrictions: { 162 | setChromeRestrictions(); 163 | break; 164 | } 165 | case R.id.clear_chrome_restrictions: { 166 | clearChromeRestrictions(); 167 | break; 168 | } 169 | case R.id.enable_forwarding: { 170 | enableForwarding(); 171 | break; 172 | } 173 | case R.id.disable_forwarding: { 174 | disableForwarding(); 175 | break; 176 | } 177 | case R.id.send_intent: { 178 | sendIntent(); 179 | break; 180 | } 181 | case R.id.remove_profile: { 182 | mButtonRemoveProfile.setEnabled(false); 183 | removeProfile(); 184 | break; 185 | } 186 | } 187 | } 188 | 189 | @Override 190 | public void onCheckedChanged(CompoundButton compoundButton, boolean checked) { 191 | switch (compoundButton.getId()) { 192 | case R.id.toggle_calculator: { 193 | setAppEnabled(PACKAGE_NAME_CALCULATOR, checked); 194 | mCalculatorEnabled = checked; 195 | break; 196 | } 197 | case R.id.toggle_chrome: { 198 | setAppEnabled(PACKAGE_NAME_CHROME, checked); 199 | mChromeEnabled = checked; 200 | break; 201 | } 202 | } 203 | } 204 | 205 | /** 206 | * Enables or disables the specified app in this profile. 207 | * 208 | * @param packageName The package name of the target app. 209 | * @param enabled Pass true to enable the app. 210 | */ 211 | private void setAppEnabled(String packageName, boolean enabled) { 212 | Activity activity = getActivity(); 213 | if (null == activity) { 214 | return; 215 | } 216 | PackageManager packageManager = activity.getPackageManager(); 217 | DevicePolicyManager devicePolicyManager = 218 | (DevicePolicyManager) activity.getSystemService(Context.DEVICE_POLICY_SERVICE); 219 | try { 220 | int packageFlags; 221 | if(Build.VERSION.SDK_INT < 24){ 222 | //noinspection deprecation 223 | packageFlags = PackageManager.GET_UNINSTALLED_PACKAGES; 224 | }else{ 225 | packageFlags = PackageManager.MATCH_UNINSTALLED_PACKAGES; 226 | } 227 | ApplicationInfo applicationInfo = packageManager.getApplicationInfo(packageName, 228 | packageFlags); 229 | // Here, we check the ApplicationInfo of the target app, and see if the flags have 230 | // ApplicationInfo.FLAG_INSTALLED turned on using bitwise operation. 231 | if (0 == (applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED)) { 232 | // If the app is not installed in this profile, we can enable it by 233 | // DPM.enableSystemApp 234 | if (enabled) { 235 | devicePolicyManager.enableSystemApp( 236 | BasicDeviceAdminReceiver.getComponentName(activity), packageName); 237 | } else { 238 | // But we cannot disable the app since it is already disabled 239 | Log.e(TAG, "Cannot disable this app: " + packageName); 240 | return; 241 | } 242 | } else { 243 | // If the app is already installed, we can enable or disable it by 244 | // DPM.setApplicationHidden 245 | devicePolicyManager.setApplicationHidden( 246 | BasicDeviceAdminReceiver.getComponentName(activity), packageName, !enabled); 247 | } 248 | Toast.makeText(activity, enabled ? R.string.enabled : R.string.disabled, 249 | Toast.LENGTH_SHORT).show(); 250 | } catch (PackageManager.NameNotFoundException e) { 251 | Log.e(TAG, "The app cannot be found: " + packageName, e); 252 | } 253 | } 254 | 255 | /** 256 | * Sets restrictions to Chrome 257 | */ 258 | private void setChromeRestrictions() { 259 | final Activity activity = getActivity(); 260 | if (null == activity) { 261 | return; 262 | } 263 | final DevicePolicyManager manager = 264 | (DevicePolicyManager) activity.getSystemService(Context.DEVICE_POLICY_SERVICE); 265 | final Bundle settings = new Bundle(); 266 | settings.putString("EditBookmarksEnabled", "false"); 267 | settings.putString("IncognitoModeAvailability", "1"); 268 | settings.putString("ManagedBookmarks", 269 | "[{\"name\": \"Chromium\", \"url\": \"http://chromium.org\"}, " + 270 | "{\"name\": \"Google\", \"url\": \"https://www.google.com\"}]"); 271 | settings.putString("DefaultSearchProviderEnabled", "true"); 272 | settings.putString("DefaultSearchProviderName", "\"LMGTFY\""); 273 | settings.putString("DefaultSearchProviderSearchURL", 274 | "\"http://lmgtfy.com/?q={searchTerms}\""); 275 | settings.putString("URLBlacklist", "[\"example.com\", \"example.org\"]"); 276 | StringBuilder message = new StringBuilder("Setting Chrome restrictions:"); 277 | for (String key : settings.keySet()) { 278 | message.append("\n"); 279 | message.append(key); 280 | message.append(": "); 281 | message.append(settings.getString(key)); 282 | } 283 | ScrollView view = new ScrollView(activity); 284 | TextView text = new TextView(activity); 285 | text.setText(message); 286 | int size = (int) activity.getResources().getDimension(R.dimen.activity_horizontal_margin); 287 | view.setPadding(size, size, size, size); 288 | view.addView(text); 289 | new AlertDialog.Builder(activity) 290 | .setView(view) 291 | .setNegativeButton(android.R.string.cancel, null) 292 | .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { 293 | @Override 294 | public void onClick(DialogInterface dialogInterface, int i) { 295 | // This is how you can set restrictions to an app. 296 | // The format for settings in Bundle differs from app to app. 297 | manager.setApplicationRestrictions 298 | (BasicDeviceAdminReceiver.getComponentName(activity), 299 | PACKAGE_NAME_CHROME, settings); 300 | Toast.makeText(activity, R.string.restrictions_set, 301 | Toast.LENGTH_SHORT).show(); 302 | } 303 | }) 304 | .show(); 305 | } 306 | 307 | /** 308 | * Clears restrictions to Chrome 309 | */ 310 | private void clearChromeRestrictions() { 311 | final Activity activity = getActivity(); 312 | if (null == activity) { 313 | return; 314 | } 315 | final DevicePolicyManager manager = 316 | (DevicePolicyManager) activity.getSystemService(Context.DEVICE_POLICY_SERVICE); 317 | // In order to clear restrictions, pass null as the restriction Bundle for 318 | // setApplicationRestrictions 319 | manager.setApplicationRestrictions 320 | (BasicDeviceAdminReceiver.getComponentName(activity), 321 | PACKAGE_NAME_CHROME, null); 322 | Toast.makeText(activity, R.string.cleared, Toast.LENGTH_SHORT).show(); 323 | } 324 | 325 | /** 326 | * Enables forwarding of share intent between private account and managed profile. 327 | */ 328 | private void enableForwarding() { 329 | Activity activity = getActivity(); 330 | if (null == activity || activity.isFinishing()) { 331 | return; 332 | } 333 | DevicePolicyManager manager = 334 | (DevicePolicyManager) activity.getSystemService(Context.DEVICE_POLICY_SERVICE); 335 | try { 336 | IntentFilter filter = new IntentFilter(Intent.ACTION_SEND); 337 | filter.addDataType("text/plain"); 338 | filter.addDataType("image/jpeg"); 339 | // This is how you can register an IntentFilter as allowed pattern of Intent forwarding 340 | manager.addCrossProfileIntentFilter(BasicDeviceAdminReceiver.getComponentName(activity), 341 | filter, FLAG_MANAGED_CAN_ACCESS_PARENT | FLAG_PARENT_CAN_ACCESS_MANAGED); 342 | } catch (IntentFilter.MalformedMimeTypeException e) { 343 | e.printStackTrace(); 344 | } 345 | } 346 | 347 | /** 348 | * Disables forwarding of all intents. 349 | */ 350 | private void disableForwarding() { 351 | Activity activity = getActivity(); 352 | if (null == activity || activity.isFinishing()) { 353 | return; 354 | } 355 | DevicePolicyManager manager = 356 | (DevicePolicyManager) activity.getSystemService(Context.DEVICE_POLICY_SERVICE); 357 | manager.clearCrossProfileIntentFilters(BasicDeviceAdminReceiver.getComponentName(activity)); 358 | } 359 | 360 | /** 361 | * Sends a sample intent of a plain text message. This is just a utility function to see how 362 | * the intent forwarding works. 363 | */ 364 | private void sendIntent() { 365 | Activity activity = getActivity(); 366 | if (null == activity || activity.isFinishing()) { 367 | return; 368 | } 369 | DevicePolicyManager manager = 370 | (DevicePolicyManager) activity.getSystemService(Context.DEVICE_POLICY_SERVICE); 371 | Intent intent = new Intent(Intent.ACTION_SEND); 372 | intent.setType("text/plain"); 373 | intent.putExtra(Intent.EXTRA_TEXT, 374 | manager.isProfileOwnerApp(activity.getApplicationContext().getPackageName()) 375 | ? "From the managed account" : "From the primary account"); 376 | try { 377 | startActivity(intent); 378 | Log.d(TAG, "A sample intent was sent."); 379 | } catch (ActivityNotFoundException e) { 380 | Toast.makeText(activity, R.string.activity_not_found, Toast.LENGTH_SHORT).show(); 381 | } 382 | } 383 | 384 | /** 385 | * Wipes out all the data related to this managed profile. 386 | */ 387 | private void removeProfile() { 388 | Activity activity = getActivity(); 389 | if (null == activity || activity.isFinishing()) { 390 | return; 391 | } 392 | DevicePolicyManager manager = 393 | (DevicePolicyManager) activity.getSystemService(Context.DEVICE_POLICY_SERVICE); 394 | manager.wipeData(0); 395 | // The screen turns off here 396 | } 397 | 398 | } 399 | -------------------------------------------------------------------------------- /Application/src/main/java/com/example/android/basicmanagedprofile/EnableProfileActivity.java: -------------------------------------------------------------------------------- 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.admin.DevicePolicyManager; 21 | import android.content.ComponentName; 22 | import android.content.Context; 23 | import android.content.Intent; 24 | import android.os.Bundle; 25 | import android.view.View; 26 | 27 | /** 28 | * This activity is started after the provisioning is complete in {@link BasicDeviceAdminReceiver}. 29 | */ 30 | public class EnableProfileActivity extends Activity implements View.OnClickListener { 31 | 32 | @Override 33 | protected void onCreate(Bundle savedInstanceState) { 34 | super.onCreate(savedInstanceState); 35 | if (null == savedInstanceState) { 36 | // Important: After the profile has been created, the MDM must enable it for corporate 37 | // apps to become visible in the launcher. 38 | enableProfile(); 39 | } 40 | // This is just a friendly shortcut to the main screen. 41 | setContentView(R.layout.activity_setup); 42 | findViewById(R.id.icon).setOnClickListener(this); 43 | } 44 | 45 | private void enableProfile() { 46 | DevicePolicyManager manager = 47 | (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE); 48 | ComponentName componentName = BasicDeviceAdminReceiver.getComponentName(this); 49 | // This is the name for the newly created managed profile. 50 | manager.setProfileName(componentName, getString(R.string.profile_name)); 51 | // We enable the profile here. 52 | manager.setProfileEnabled(componentName); 53 | } 54 | 55 | @Override 56 | public void onClick(View view) { 57 | switch (view.getId()) { 58 | case R.id.icon: { 59 | // Opens up the main screen 60 | startActivity(new Intent(this, MainActivity.class)); 61 | finish(); 62 | break; 63 | } 64 | } 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /Application/src/main/java/com/example/android/basicmanagedprofile/MainActivity.java: -------------------------------------------------------------------------------- 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.admin.DevicePolicyManager; 21 | import android.content.Context; 22 | import android.os.Bundle; 23 | 24 | public class MainActivity extends Activity { 25 | 26 | @Override 27 | protected void onCreate(Bundle savedInstanceState) { 28 | super.onCreate(savedInstanceState); 29 | setContentView(R.layout.activity_main_real); 30 | if (savedInstanceState == null) { 31 | DevicePolicyManager manager = (DevicePolicyManager) 32 | getSystemService(Context.DEVICE_POLICY_SERVICE); 33 | if (manager.isProfileOwnerApp(getApplicationContext().getPackageName())) { 34 | // If the managed profile is already set up, we show the main screen. 35 | showMainFragment(); 36 | } else { 37 | // If not, we show the set up screen. 38 | showSetupProfile(); 39 | } 40 | } 41 | } 42 | 43 | private void showSetupProfile() { 44 | getFragmentManager().beginTransaction() 45 | .replace(R.id.container, SetupProfileFragment.newInstance()) 46 | .commit(); 47 | } 48 | 49 | private void showMainFragment() { 50 | getFragmentManager().beginTransaction() 51 | .add(R.id.container, BasicManagedProfileFragment.newInstance()) 52 | .commit(); 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /Application/src/main/java/com/example/android/basicmanagedprofile/SetupProfileFragment.java: -------------------------------------------------------------------------------- 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.Fragment; 21 | import android.app.admin.DevicePolicyManager; 22 | import android.content.ComponentName; 23 | import android.content.Intent; 24 | import android.os.Build; 25 | import android.os.Bundle; 26 | import android.view.LayoutInflater; 27 | import android.view.View; 28 | import android.view.ViewGroup; 29 | import android.widget.Toast; 30 | 31 | /** 32 | * This {@link Fragment} handles initiation of managed profile provisioning. 33 | */ 34 | public class SetupProfileFragment extends Fragment implements View.OnClickListener { 35 | 36 | private static final int REQUEST_PROVISION_MANAGED_PROFILE = 1; 37 | 38 | public static SetupProfileFragment newInstance() { 39 | return new SetupProfileFragment(); 40 | } 41 | 42 | public SetupProfileFragment() { 43 | } 44 | 45 | @Override 46 | public View onCreateView(LayoutInflater inflater, ViewGroup container, 47 | Bundle savedInstanceState) { 48 | return inflater.inflate(R.layout.fragment_setup_profile, container, false); 49 | } 50 | 51 | @Override 52 | public void onViewCreated(View view, Bundle savedInstanceState) { 53 | view.findViewById(R.id.set_up_profile).setOnClickListener(this); 54 | } 55 | 56 | @Override 57 | public void onClick(View view) { 58 | switch (view.getId()) { 59 | case R.id.set_up_profile: { 60 | provisionManagedProfile(); 61 | break; 62 | } 63 | } 64 | } 65 | 66 | /** 67 | * Initiates the managed profile provisioning. If we already have a managed profile set up on 68 | * this device, we will get an error dialog in the following provisioning phase. 69 | */ 70 | private void provisionManagedProfile() { 71 | Activity activity = getActivity(); 72 | if (null == activity) { 73 | return; 74 | } 75 | Intent intent = new Intent(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE); 76 | 77 | // Use a different intent extra below M to configure the admin component. 78 | if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { 79 | //noinspection deprecation 80 | intent.putExtra(DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME, 81 | activity.getApplicationContext().getPackageName()); 82 | } else { 83 | final ComponentName component = new ComponentName(activity, 84 | BasicDeviceAdminReceiver.class.getName()); 85 | intent.putExtra(DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME, 86 | component); 87 | } 88 | 89 | if (intent.resolveActivity(activity.getPackageManager()) != null) { 90 | startActivityForResult(intent, REQUEST_PROVISION_MANAGED_PROFILE); 91 | activity.finish(); 92 | } else { 93 | Toast.makeText(activity, "Device provisioning is not enabled. Stopping.", 94 | Toast.LENGTH_SHORT).show(); 95 | } 96 | } 97 | 98 | @Override 99 | public void onActivityResult(int requestCode, int resultCode, Intent data) { 100 | if (requestCode == REQUEST_PROVISION_MANAGED_PROFILE) { 101 | if (resultCode == Activity.RESULT_OK) { 102 | Toast.makeText(getActivity(), "Provisioning done.", Toast.LENGTH_SHORT).show(); 103 | } else { 104 | Toast.makeText(getActivity(), "Provisioning failed.", Toast.LENGTH_SHORT).show(); 105 | } 106 | return; 107 | } 108 | super.onActivityResult(requestCode, resultCode, data); 109 | } 110 | 111 | } 112 | -------------------------------------------------------------------------------- /Application/src/main/res/drawable-hdpi/tile.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlearchive/android-BasicManagedProfile/8441697d613c4a8e8f70f57aac6f103d242de35c/Application/src/main/res/drawable-hdpi/tile.9.png -------------------------------------------------------------------------------- /Application/src/main/res/drawable-xxhdpi/badge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlearchive/android-BasicManagedProfile/8441697d613c4a8e8f70f57aac6f103d242de35c/Application/src/main/res/drawable-xxhdpi/badge.png -------------------------------------------------------------------------------- /Application/src/main/res/drawable/ic_launcher_badged.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | 25 | 26 | -------------------------------------------------------------------------------- /Application/src/main/res/layout/activity_main_real.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 24 | -------------------------------------------------------------------------------- /Application/src/main/res/layout/activity_setup.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 25 | 26 | 31 | 32 | 37 | 38 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /Application/src/main/res/layout/fragment_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 22 | 23 | 31 | 32 | 37 | 38 | 39 | 40 | 46 | 47 | 48 | 49 | 56 | 57 |