Java tutorial
/* * Copyright (C) 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.afwsamples.testdpc.provision; import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE; import static android.app.admin.DevicePolicyManager.PERMISSION_GRANT_STATE_GRANTED; import static com.afwsamples.testdpc.DeviceAdminReceiver.getComponentName; import android.accounts.Account; import android.accounts.AccountManager; import android.annotation.TargetApi; import android.app.admin.DevicePolicyManager; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PermissionInfo; import android.os.Build; import android.os.PersistableBundle; import android.support.v4.os.BuildCompat; import android.util.Log; import com.afwsamples.testdpc.AddAccountActivity; import com.afwsamples.testdpc.EnableDeviceOwnerActivity; import com.afwsamples.testdpc.EnableProfileActivity; import com.afwsamples.testdpc.common.LaunchIntentUtil; import com.afwsamples.testdpc.common.Util; import com.afwsamples.testdpc.cosu.EnableCosuActivity; import java.util.ArrayList; import java.util.Arrays; import java.util.List; /** * Task executed after provisioning is done indicated by either the * {@link DevicePolicyManager#ACTION_PROVISIONING_SUCCESSFUL} activity intent or the * {@link android.app.admin.DeviceAdminReceiver#onProfileProvisioningComplete(Context, Intent)} * broadcast. * * <p>Operations performed: * <ul> * <li>self-grant all run-time permissions</li> * <li>enable the launcher activity</li> * <li>start waiting for first account ready broadcast</li> * </ul> */ public class PostProvisioningTask { private static final String TAG = "PostProvisioningTask"; private static final String SETUP_MANAGEMENT_LAUNCH_ACTIVITY = "com.afwsamples.testdpc.SetupManagementLaunchActivity"; private static final String POST_PROV_PREFS = "post_prov_prefs"; private static final String KEY_POST_PROV_DONE = "key_post_prov_done"; private final Context mContext; private final DevicePolicyManager mDevicePolicyManager; private final SharedPreferences mSharedPrefs; public PostProvisioningTask(Context context) { mContext = context; mDevicePolicyManager = context.getSystemService(DevicePolicyManager.class); mSharedPrefs = context.getSharedPreferences(POST_PROV_PREFS, Context.MODE_PRIVATE); } public boolean performPostProvisioningOperations(Intent intent) { if (isPostProvisioningDone()) { return false; } markPostProvisioningDone(); // From M onwards, permissions are not auto-granted, so we need to manually grant // permissions for TestDPC. if (Util.isAtLeastM()) { autoGrantRequestedPermissionsToSelf(); } // Retreive the admin extras bundle, which we can use to determine the original context for // TestDPCs launch. PersistableBundle extras = intent.getParcelableExtra(EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE); if (BuildCompat.isAtLeastO()) { maybeSetAffiliationIds(extras); } // Hide the setup launcher when this app is the admin mContext.getPackageManager().setComponentEnabledSetting( new ComponentName(mContext, SETUP_MANAGEMENT_LAUNCH_ACTIVITY), PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP); return true; } public Intent getPostProvisioningLaunchIntent(Intent intent) { // Enable the profile after provisioning is complete. Intent launch; // Retreive the admin extras bundle, which we can use to determine the original context for // TestDPCs launch. PersistableBundle extras = intent.getParcelableExtra(EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE); String packageName = mContext.getPackageName(); boolean synchronousAuthLaunch = LaunchIntentUtil.isSynchronousAuthLaunch(extras); boolean cosuLaunch = LaunchIntentUtil.isCosuLaunch(extras); boolean isProfileOwner = mDevicePolicyManager.isProfileOwnerApp(packageName); boolean isDeviceOwner = mDevicePolicyManager.isDeviceOwnerApp(packageName); // Drop out quickly if we're neither profile or device owner. if (!isProfileOwner && !isDeviceOwner) { return null; } if (isProfileOwner) { launch = new Intent(mContext, EnableProfileActivity.class); } else if (cosuLaunch) { launch = new Intent(mContext, EnableCosuActivity.class); launch.putExtra(EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE, extras); } else { launch = new Intent(mContext, EnableDeviceOwnerActivity.class); } if (synchronousAuthLaunch) { String accountName = LaunchIntentUtil.getAddedAccountName(extras); if (accountName != null) { launch.putExtra(LaunchIntentUtil.EXTRA_ACCOUNT_NAME, accountName); } } // For synchronous auth cases, we can assume accounts are already setup (or will be shortly, // as account migration for Profile Owner is asynchronous). For COSU we don't want to show // the account option to the user, as no accounts should be added for now. // In other cases, offer to add an account to the newly configured device/profile. if (!synchronousAuthLaunch && !cosuLaunch) { AccountManager accountManager = AccountManager.get(mContext); Account[] accounts = accountManager.getAccounts(); if (accounts != null && accounts.length == 0) { // Add account after provisioning is complete. Intent addAccountIntent = new Intent(mContext, AddAccountActivity.class); addAccountIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); addAccountIntent.putExtra(AddAccountActivity.EXTRA_NEXT_ACTIVITY_INTENT, launch); return addAccountIntent; } } launch.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); return launch; } private void markPostProvisioningDone() { mSharedPrefs.edit().putBoolean(KEY_POST_PROV_DONE, true).commit(); } private boolean isPostProvisioningDone() { return mSharedPrefs.getBoolean(KEY_POST_PROV_DONE, false); } @TargetApi(Build.VERSION_CODES.O) private void maybeSetAffiliationIds(PersistableBundle extras) { if (extras == null) { return; } String affiliationId = extras.getString(LaunchIntentUtil.EXTRA_AFFILIATION_ID); if (affiliationId != null) { mDevicePolicyManager.setAffiliationIds(getComponentName(mContext), Arrays.asList(affiliationId)); } } @TargetApi(Build.VERSION_CODES.M) private void autoGrantRequestedPermissionsToSelf() { String packageName = mContext.getPackageName(); ComponentName adminComponentName = getComponentName(mContext); List<String> permissions = getRuntimePermissions(mContext.getPackageManager(), packageName); for (String permission : permissions) { boolean success = mDevicePolicyManager.setPermissionGrantState(adminComponentName, packageName, permission, PERMISSION_GRANT_STATE_GRANTED); Log.d(TAG, "Auto-granting " + permission + ", success: " + success); if (!success) { Log.e(TAG, "Failed to auto grant permission to self: " + permission); } } } private List<String> getRuntimePermissions(PackageManager packageManager, String packageName) { List<String> permissions = new ArrayList<>(); PackageInfo packageInfo; try { packageInfo = packageManager.getPackageInfo(packageName, PackageManager.GET_PERMISSIONS); } catch (PackageManager.NameNotFoundException e) { Log.e(TAG, "Could not retrieve info about the package: " + packageName, e); return permissions; } if (packageInfo != null && packageInfo.requestedPermissions != null) { for (String requestedPerm : packageInfo.requestedPermissions) { if (isRuntimePermission(packageManager, requestedPerm)) { permissions.add(requestedPerm); } } } return permissions; } private boolean isRuntimePermission(PackageManager packageManager, String permission) { try { PermissionInfo pInfo = packageManager.getPermissionInfo(permission, 0); if (pInfo != null) { if ((pInfo.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE) == PermissionInfo.PROTECTION_DANGEROUS) { return true; } } } catch (PackageManager.NameNotFoundException e) { Log.i(TAG, "Could not retrieve info about the permission: " + permission); } return false; } }