Utils.java revision 72023ca7b7a818fa33e0303baf6f5baef05b5f1b
1d5e4c42542dd96d8940912cc20dff20fa48da0d9Sander Alewijnse/*
2d5e4c42542dd96d8940912cc20dff20fa48da0d9Sander Alewijnse * Copyright 2014, The Android Open Source Project
3d5e4c42542dd96d8940912cc20dff20fa48da0d9Sander Alewijnse *
4d5e4c42542dd96d8940912cc20dff20fa48da0d9Sander Alewijnse * Licensed under the Apache License, Version 2.0 (the "License");
5d5e4c42542dd96d8940912cc20dff20fa48da0d9Sander Alewijnse * you may not use this file except in compliance with the License.
6d5e4c42542dd96d8940912cc20dff20fa48da0d9Sander Alewijnse * You may obtain a copy of the License at
7d5e4c42542dd96d8940912cc20dff20fa48da0d9Sander Alewijnse *
8d5e4c42542dd96d8940912cc20dff20fa48da0d9Sander Alewijnse *     http://www.apache.org/licenses/LICENSE-2.0
9d5e4c42542dd96d8940912cc20dff20fa48da0d9Sander Alewijnse *
10d5e4c42542dd96d8940912cc20dff20fa48da0d9Sander Alewijnse * Unless required by applicable law or agreed to in writing, software
11d5e4c42542dd96d8940912cc20dff20fa48da0d9Sander Alewijnse * distributed under the License is distributed on an "AS IS" BASIS,
12d5e4c42542dd96d8940912cc20dff20fa48da0d9Sander Alewijnse * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13d5e4c42542dd96d8940912cc20dff20fa48da0d9Sander Alewijnse * See the License for the specific language governing permissions and
14d5e4c42542dd96d8940912cc20dff20fa48da0d9Sander Alewijnse * limitations under the License.
15d5e4c42542dd96d8940912cc20dff20fa48da0d9Sander Alewijnse */
16d5e4c42542dd96d8940912cc20dff20fa48da0d9Sander Alewijnse
1772023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franzpackage com.android.managedprovisioning.common;
18d5e4c42542dd96d8940912cc20dff20fa48da0d9Sander Alewijnse
193128ba4542f3c4c90790af0564e75950c8900961Alan Treadwayimport static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE;
20eee36899e6a73cf7635b11bb1723a411f324ea91Steven Ngimport static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE;
213128ba4542f3c4c90790af0564e75950c8900961Alan Treadwayimport static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE;
223128ba4542f3c4c90790af0564e75950c8900961Alan Treadwayimport static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE;
233128ba4542f3c4c90790af0564e75950c8900961Alan Treadwayimport static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_USER;
243128ba4542f3c4c90790af0564e75950c8900961Alan Treadwayimport static android.app.admin.DevicePolicyManager.MIME_TYPE_PROVISIONING_NFC;
253128ba4542f3c4c90790af0564e75950c8900961Alan Treadwayimport static android.nfc.NfcAdapter.ACTION_NDEF_DISCOVERED;
263128ba4542f3c4c90790af0564e75950c8900961Alan Treadwayimport static java.nio.charset.StandardCharsets.UTF_8;
273128ba4542f3c4c90790af0564e75950c8900961Alan Treadway
283128ba4542f3c4c90790af0564e75950c8900961Alan Treadwayimport android.accounts.Account;
293128ba4542f3c4c90790af0564e75950c8900961Alan Treadwayimport android.accounts.AccountManager;
303128ba4542f3c4c90790af0564e75950c8900961Alan Treadwayimport android.accounts.AccountManagerFuture;
313128ba4542f3c4c90790af0564e75950c8900961Alan Treadwayimport android.accounts.AuthenticatorException;
323128ba4542f3c4c90790af0564e75950c8900961Alan Treadwayimport android.accounts.OperationCanceledException;
3384e56f5cfc1d45b3983dd553096182e774d8cb2cJoe Delfinoimport android.app.admin.DevicePolicyManager;
349a42f2b64dada715248aec7c898f983375a395eeAlan Treadwayimport android.content.ComponentName;
350b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevotimport android.content.Context;
369a42f2b64dada715248aec7c898f983375a395eeAlan Treadwayimport android.content.Intent;
370b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevotimport android.content.pm.ActivityInfo;
38d5e4c42542dd96d8940912cc20dff20fa48da0d9Sander Alewijnseimport android.content.pm.ApplicationInfo;
39d5e4c42542dd96d8940912cc20dff20fa48da0d9Sander Alewijnseimport android.content.pm.IPackageManager;
400b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevotimport android.content.pm.PackageInfo;
41d5e4c42542dd96d8940912cc20dff20fa48da0d9Sander Alewijnseimport android.content.pm.PackageManager;
420b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevotimport android.content.pm.PackageManager.NameNotFoundException;
4384e56f5cfc1d45b3983dd553096182e774d8cb2cJoe Delfinoimport android.content.pm.UserInfo;
443128ba4542f3c4c90790af0564e75950c8900961Alan Treadwayimport android.nfc.NdefMessage;
453128ba4542f3c4c90790af0564e75950c8900961Alan Treadwayimport android.nfc.NdefRecord;
463128ba4542f3c4c90790af0564e75950c8900961Alan Treadwayimport android.nfc.NfcAdapter;
47a5daf2dfdbb7c1b1ea5b930cc7836cf67778dde4Sudheer Shankaimport android.os.Bundle;
483128ba4542f3c4c90790af0564e75950c8900961Alan Treadwayimport android.os.Parcelable;
49ca9c867e27a1af69960c6c91d90177ea45c78d09Alan Treadwayimport android.os.Process;
50d5e4c42542dd96d8940912cc20dff20fa48da0d9Sander Alewijnseimport android.os.RemoteException;
51d5e4c42542dd96d8940912cc20dff20fa48da0d9Sander Alewijnseimport android.os.ServiceManager;
52d0f2928a28d38ce8344b7f15fbfec97aebec0db6Joe Delfinoimport android.os.UserHandle;
5384e56f5cfc1d45b3983dd553096182e774d8cb2cJoe Delfinoimport android.os.UserManager;
54a5daf2dfdbb7c1b1ea5b930cc7836cf67778dde4Sudheer Shankaimport android.provider.Settings.Global;
55a5daf2dfdbb7c1b1ea5b930cc7836cf67778dde4Sudheer Shankaimport android.provider.Settings.Secure;
560b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevotimport android.text.TextUtils;
573efa83ac5074f40be2e1f275d492cf4175e7eb4bSander Alewijnseimport android.util.Base64;
58d5e4c42542dd96d8940912cc20dff20fa48da0d9Sander Alewijnse
59a5daf2dfdbb7c1b1ea5b930cc7836cf67778dde4Sudheer Shankaimport java.io.IOException;
60ba113214d1820f32e5132cd83a06fa1eaedd2866Alan Treadwayimport java.lang.Integer;
613128ba4542f3c4c90790af0564e75950c8900961Alan Treadwayimport java.lang.String;
623128ba4542f3c4c90790af0564e75950c8900961Alan Treadwayimport java.nio.charset.StandardCharsets;
63d5e4c42542dd96d8940912cc20dff20fa48da0d9Sander Alewijnseimport java.util.HashSet;
649a42f2b64dada715248aec7c898f983375a395eeAlan Treadwayimport java.util.List;
65d5e4c42542dd96d8940912cc20dff20fa48da0d9Sander Alewijnseimport java.util.Set;
66ca9c867e27a1af69960c6c91d90177ea45c78d09Alan Treadwayimport java.util.concurrent.TimeUnit;
67d5e4c42542dd96d8940912cc20dff20fa48da0d9Sander Alewijnse
6872023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franzimport com.android.managedprovisioning.FinalizationActivity;
6972023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franzimport com.android.managedprovisioning.ProvisionLogger;
7072023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franzimport com.android.managedprovisioning.ProvisioningParams;
7172023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franzimport com.android.managedprovisioning.TrampolineActivity;
7272023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz
73d5e4c42542dd96d8940912cc20dff20fa48da0d9Sander Alewijnse/**
74d5e4c42542dd96d8940912cc20dff20fa48da0d9Sander Alewijnse * Class containing various auxiliary methods.
75d5e4c42542dd96d8940912cc20dff20fa48da0d9Sander Alewijnse */
76d5e4c42542dd96d8940912cc20dff20fa48da0d9Sander Alewijnsepublic class Utils {
779f97ed0a3eb724b23f7322a0f425bc4f6e98e6d0Benjamin Franz    private static final int ACCOUNT_COPY_TIMEOUT_SECONDS = 60 * 3;  // 3 minutes
78ca9c867e27a1af69960c6c91d90177ea45c78d09Alan Treadway
7972023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz    public Utils() {}
809a42f2b64dada715248aec7c898f983375a395eeAlan Treadway
8172023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz    /**
8272023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     * Returns the currently installed system apps on a given user.
8372023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     *
8472023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     * <p>Calls into the {@link IPackageManager} to retrieve all installed packages on the given
8572023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     * user and returns the package names of all system apps.
8672023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     *
8772023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     * @param ipm an {@link IPackageManager} object
8872023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     * @param userId the id of the user we are interested in
8972023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     */
9072023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz    public Set<String> getCurrentSystemApps(IPackageManager ipm, int userId) {
91d5e4c42542dd96d8940912cc20dff20fa48da0d9Sander Alewijnse        Set<String> apps = new HashSet<String>();
92d5e4c42542dd96d8940912cc20dff20fa48da0d9Sander Alewijnse        List<ApplicationInfo> aInfos = null;
93d5e4c42542dd96d8940912cc20dff20fa48da0d9Sander Alewijnse        try {
94d5e4c42542dd96d8940912cc20dff20fa48da0d9Sander Alewijnse            aInfos = ipm.getInstalledApplications(
95d5e4c42542dd96d8940912cc20dff20fa48da0d9Sander Alewijnse                    PackageManager.GET_UNINSTALLED_PACKAGES, userId).getList();
96d5e4c42542dd96d8940912cc20dff20fa48da0d9Sander Alewijnse        } catch (RemoteException neverThrown) {
97d5e4c42542dd96d8940912cc20dff20fa48da0d9Sander Alewijnse            ProvisionLogger.loge("This should not happen.", neverThrown);
98d5e4c42542dd96d8940912cc20dff20fa48da0d9Sander Alewijnse        }
99d5e4c42542dd96d8940912cc20dff20fa48da0d9Sander Alewijnse        for (ApplicationInfo aInfo : aInfos) {
100d5e4c42542dd96d8940912cc20dff20fa48da0d9Sander Alewijnse            if ((aInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
101d5e4c42542dd96d8940912cc20dff20fa48da0d9Sander Alewijnse                apps.add(aInfo.packageName);
102d5e4c42542dd96d8940912cc20dff20fa48da0d9Sander Alewijnse            }
103d5e4c42542dd96d8940912cc20dff20fa48da0d9Sander Alewijnse        }
104d5e4c42542dd96d8940912cc20dff20fa48da0d9Sander Alewijnse        return apps;
105d5e4c42542dd96d8940912cc20dff20fa48da0d9Sander Alewijnse    }
106d5e4c42542dd96d8940912cc20dff20fa48da0d9Sander Alewijnse
10772023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz    /**
10872023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     * Disables a given component in a given user.
10972023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     *
11072023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     * @param toDisable the component that should be disabled
11172023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     * @param userId the id of the user where the component should be disabled.
11272023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     */
11372023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz    public void disableComponent(ComponentName toDisable, int userId) {
11472023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz        disableComponent(IPackageManager.Stub.asInterface(ServiceManager.getService("package")),
11572023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz                toDisable, userId);
11672023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz    }
117d5e4c42542dd96d8940912cc20dff20fa48da0d9Sander Alewijnse
11872023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz    /**
11972023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     * Disables a given component in a given user.
12072023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     *
12172023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     * @param ipm an {@link IPackageManager} object
12272023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     * @param toDisable the component that should be disabled
12372023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     * @param userId the id of the user where the component should be disabled.
12472023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     */
12572023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz    public void disableComponent(IPackageManager ipm, ComponentName toDisable, int userId) {
12672023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz        try {
127d5e4c42542dd96d8940912cc20dff20fa48da0d9Sander Alewijnse            ipm.setComponentEnabledSetting(toDisable,
128d5e4c42542dd96d8940912cc20dff20fa48da0d9Sander Alewijnse                    PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP,
129d5e4c42542dd96d8940912cc20dff20fa48da0d9Sander Alewijnse                    userId);
130d5e4c42542dd96d8940912cc20dff20fa48da0d9Sander Alewijnse        } catch (RemoteException neverThrown) {
131d5e4c42542dd96d8940912cc20dff20fa48da0d9Sander Alewijnse            ProvisionLogger.loge("This should not happen.", neverThrown);
132d5e4c42542dd96d8940912cc20dff20fa48da0d9Sander Alewijnse        } catch (Exception e) {
133d5e4c42542dd96d8940912cc20dff20fa48da0d9Sander Alewijnse            ProvisionLogger.logw("Component not found, not disabling it: "
134d5e4c42542dd96d8940912cc20dff20fa48da0d9Sander Alewijnse                + toDisable.toShortString());
135d5e4c42542dd96d8940912cc20dff20fa48da0d9Sander Alewijnse        }
136d5e4c42542dd96d8940912cc20dff20fa48da0d9Sander Alewijnse    }
1370b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevot
1380b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevot    /**
1390b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevot     * Check the validity of the admin component name supplied, or try to infer this componentName
1400b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevot     * from the package.
1410b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevot     *
1420b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevot     * We are supporting lookup by package name for legacy reasons.
1430b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevot     *
1440b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevot     * If mdmComponentName is supplied (not null):
1450b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevot     * mdmPackageName is ignored.
1460b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevot     * Check that the package of mdmComponentName is installed, that mdmComponentName is a
1470b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevot     * receiver in this package, and return it.
1480b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevot     *
1490b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevot     * Otherwise:
1500b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevot     * mdmPackageName must be supplied (not null).
1510b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevot     * Check that this package is installed, try to infer a potential device admin in this package,
1520b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevot     * and return it.
1530b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevot     */
15472023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz    // ToDo: Add unit tests
15572023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz    public ComponentName findDeviceAdmin(String mdmPackageName,
1560b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevot            ComponentName mdmComponentName, Context c) throws IllegalProvisioningArgumentException {
1570b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevot        if (mdmComponentName != null) {
1580b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevot            mdmPackageName = mdmComponentName.getPackageName();
1590b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevot        }
1600b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevot        if (mdmPackageName == null) {
1610b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevot            throw new IllegalProvisioningArgumentException("Neither the package name nor the"
1620b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevot                    + " component name of the admin are supplied");
1630b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevot        }
1640b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevot        PackageInfo pi;
1650b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevot        try {
1660b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevot            pi = c.getPackageManager().getPackageInfo(mdmPackageName,
1670b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevot                    PackageManager.GET_RECEIVERS);
1680b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevot        } catch (NameNotFoundException e) {
1690b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevot            throw new IllegalProvisioningArgumentException("Mdm "+ mdmPackageName
1700b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevot                    + " is not installed. ", e);
1710b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevot        }
1720b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevot        if (mdmComponentName != null) {
1730b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevot            // If the component was specified in the intent: check that it is in the manifest.
1740b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevot            checkAdminComponent(mdmComponentName, pi);
1750b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevot            return mdmComponentName;
1760b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevot        } else {
1770b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevot            // Otherwise: try to find a potential device admin in the manifest.
1780b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevot            return findDeviceAdminInPackage(mdmPackageName, pi);
1790b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevot        }
1800b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevot    }
1810b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevot
18272023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz    /**
18372023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     * Verifies that an admin component is part of a given package.
18472023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     *
18572023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     * @param mdmComponentName the admin component to be checked
18672023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     * @param pi the {@link PackageInfo} of the package to be checked.
18772023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     *
18872023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     * @throws IllegalProvisioningArgumentException if the given component is not part of the
18972023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     *         package
19072023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     */
19172023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz    private void checkAdminComponent(ComponentName mdmComponentName, PackageInfo pi)
1920b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevot            throws IllegalProvisioningArgumentException{
1930b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevot        for (ActivityInfo ai : pi.receivers) {
1940b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevot            if (mdmComponentName.getClassName().equals(ai.name)) {
1950b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevot                return;
1960b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevot            }
1970b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevot        }
1980b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevot        throw new IllegalProvisioningArgumentException("The component " + mdmComponentName
1990b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevot                + " cannot be found");
2000b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevot    }
2010b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevot
20272023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz    private ComponentName findDeviceAdminInPackage(String mdmPackageName, PackageInfo pi)
2030b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevot            throws IllegalProvisioningArgumentException {
2040b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevot        ComponentName mdmComponentName = null;
2050b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevot        for (ActivityInfo ai : pi.receivers) {
2060b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevot            if (!TextUtils.isEmpty(ai.permission) &&
2070b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevot                    ai.permission.equals(android.Manifest.permission.BIND_DEVICE_ADMIN)) {
2080b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevot                if (mdmComponentName != null) {
2090b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevot                    throw new IllegalProvisioningArgumentException("There are several "
2100b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevot                            + "device admins in " + mdmPackageName + " but no one in specified");
2110b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevot                } else {
2120b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevot                    mdmComponentName = new ComponentName(mdmPackageName, ai.name);
2130b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevot                }
2140b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevot            }
2150b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevot        }
2160b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevot        if (mdmComponentName == null) {
2170b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevot            throw new IllegalProvisioningArgumentException("There are no device admins in"
2180b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevot                    + mdmPackageName);
2190b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevot        }
2200b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevot        return mdmComponentName;
2210b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevot    }
2229a42f2b64dada715248aec7c898f983375a395eeAlan Treadway
2239a42f2b64dada715248aec7c898f983375a395eeAlan Treadway    /**
22472023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     * Returns whether the current user is the system user.
2259a42f2b64dada715248aec7c898f983375a395eeAlan Treadway     */
22672023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz    public boolean isCurrentUserSystem() {
2272a71ac51b3ae8cf0f284d69e57c763cbce8423d7Xiaohui Chen        return UserHandle.myUserId() == UserHandle.USER_SYSTEM;
228d0f2928a28d38ce8344b7f15fbfec97aebec0db6Joe Delfino    }
22984e56f5cfc1d45b3983dd553096182e774d8cb2cJoe Delfino
23072023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz    /**
23172023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     * Returns whether the device is currently managed.
23272023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     */
23372023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz    public boolean isDeviceManaged(Context context) {
23484e56f5cfc1d45b3983dd553096182e774d8cb2cJoe Delfino        DevicePolicyManager dpm =
23584e56f5cfc1d45b3983dd553096182e774d8cb2cJoe Delfino                (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE);
236981e55496221c55a77c0fe01031624cfecf75a54Makoto Onuki        return dpm.isDeviceManaged();
23784e56f5cfc1d45b3983dd553096182e774d8cb2cJoe Delfino    }
23884e56f5cfc1d45b3983dd553096182e774d8cb2cJoe Delfino
23972023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz    /**
24072023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     * Returns whether the calling user is a managed profile.
24172023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     */
24272023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz    public boolean isManagedProfile(Context context) {
24384e56f5cfc1d45b3983dd553096182e774d8cb2cJoe Delfino        UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE);
24484e56f5cfc1d45b3983dd553096182e774d8cb2cJoe Delfino        UserInfo user = um.getUserInfo(UserHandle.myUserId());
24584e56f5cfc1d45b3983dd553096182e774d8cb2cJoe Delfino        return user != null ? user.isManagedProfile() : false;
24684e56f5cfc1d45b3983dd553096182e774d8cb2cJoe Delfino    }
24784e56f5cfc1d45b3983dd553096182e774d8cb2cJoe Delfino
24874d6c14da5117ffd3458602f9f6946c531143436Sander Alewijnse    /**
24972023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     * Returns true if the given package requires an update.
25072023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     *
25172023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     * <p>There are two cases where an update is required:
25272023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     * 1. The package is not currently present on the device.
25372023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     * 2. The package is present, but the version is below the minimum supported version.
25472023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     *
25572023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     * @param packageName the package to be checked for updates
25672023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     * @param minSupportedVersion the minimum supported version
25772023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     * @param context a {@link Context} object
25874d6c14da5117ffd3458602f9f6946c531143436Sander Alewijnse     */
25972023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz    public boolean packageRequiresUpdate(String packageName, int minSupportedVersion,
26074d6c14da5117ffd3458602f9f6946c531143436Sander Alewijnse            Context context) {
26174d6c14da5117ffd3458602f9f6946c531143436Sander Alewijnse        try {
26274d6c14da5117ffd3458602f9f6946c531143436Sander Alewijnse            PackageInfo packageInfo = context.getPackageManager().getPackageInfo(packageName, 0);
26374d6c14da5117ffd3458602f9f6946c531143436Sander Alewijnse            if (packageInfo.versionCode >= minSupportedVersion) {
26474d6c14da5117ffd3458602f9f6946c531143436Sander Alewijnse                return false;
26574d6c14da5117ffd3458602f9f6946c531143436Sander Alewijnse            }
26674d6c14da5117ffd3458602f9f6946c531143436Sander Alewijnse        } catch (NameNotFoundException e) {
26774d6c14da5117ffd3458602f9f6946c531143436Sander Alewijnse            // Package not on device.
26874d6c14da5117ffd3458602f9f6946c531143436Sander Alewijnse        }
26974d6c14da5117ffd3458602f9f6946c531143436Sander Alewijnse
27074d6c14da5117ffd3458602f9f6946c531143436Sander Alewijnse        return true;
27174d6c14da5117ffd3458602f9f6946c531143436Sander Alewijnse    }
27274d6c14da5117ffd3458602f9f6946c531143436Sander Alewijnse
27372023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz    /**
27472023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     * Transforms a string into a byte array.
27572023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     *
27672023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     * @param s the string to be transformed
27772023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     */
27872023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz    public byte[] stringToByteArray(String s)
2793efa83ac5074f40be2e1f275d492cf4175e7eb4bSander Alewijnse        throws NumberFormatException {
2803efa83ac5074f40be2e1f275d492cf4175e7eb4bSander Alewijnse        try {
2813efa83ac5074f40be2e1f275d492cf4175e7eb4bSander Alewijnse            return Base64.decode(s, Base64.URL_SAFE);
2823efa83ac5074f40be2e1f275d492cf4175e7eb4bSander Alewijnse        } catch (IllegalArgumentException e) {
2833efa83ac5074f40be2e1f275d492cf4175e7eb4bSander Alewijnse            throw new NumberFormatException("Incorrect format. Should be Url-safe Base64 encoded.");
2843efa83ac5074f40be2e1f275d492cf4175e7eb4bSander Alewijnse        }
2853efa83ac5074f40be2e1f275d492cf4175e7eb4bSander Alewijnse    }
2863efa83ac5074f40be2e1f275d492cf4175e7eb4bSander Alewijnse
28772023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz    /**
28872023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     * Transforms a byte array into a string.
28972023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     *
29072023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     * @param bytes the byte array to be transformed
29172023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     */
29272023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz    public String byteArrayToString(byte[] bytes) {
2933efa83ac5074f40be2e1f275d492cf4175e7eb4bSander Alewijnse        return Base64.encodeToString(bytes, Base64.URL_SAFE | Base64.NO_PADDING | Base64.NO_WRAP);
2943efa83ac5074f40be2e1f275d492cf4175e7eb4bSander Alewijnse    }
295a5daf2dfdbb7c1b1ea5b930cc7836cf67778dde4Sudheer Shanka
29672023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz    /**
29772023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     * Marks the device as provisioning.
29872023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     *
29972023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     * <p>This will set the DEVICE_PROVISIONED to 1 as well as marking user setup complete
30072023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     * on the calling user.
30172023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     */
30272023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz    public void markDeviceProvisioned(Context context) {
303a7c379a97ce785b918a10c137e636d63a8d50010Alan Treadway        ProvisionLogger.logd("Setting DEVICE_PROVISIONED to 1");
304c78162c71e63903c6f544544cc81d1128acb6eb0Craig Lafayette        Global.putInt(context.getContentResolver(), Global.DEVICE_PROVISIONED, 1);
305a5daf2dfdbb7c1b1ea5b930cc7836cf67778dde4Sudheer Shanka
306a5daf2dfdbb7c1b1ea5b930cc7836cf67778dde4Sudheer Shanka        // Setting this flag will either cause Setup Wizard to finish immediately when it starts (if
307a5daf2dfdbb7c1b1ea5b930cc7836cf67778dde4Sudheer Shanka        // it is not already running), or when its next activity starts (if it is already running,
308a5daf2dfdbb7c1b1ea5b930cc7836cf67778dde4Sudheer Shanka        // e.g. the non-NFC flow).
309a5daf2dfdbb7c1b1ea5b930cc7836cf67778dde4Sudheer Shanka        // When either of these things happen, a home intent is fired. We catch that in
310a5daf2dfdbb7c1b1ea5b930cc7836cf67778dde4Sudheer Shanka        // HomeReceiverActivity before sending the intent to notify the mdm that provisioning is
311a5daf2dfdbb7c1b1ea5b930cc7836cf67778dde4Sudheer Shanka        // complete.
312bf793102707971d77950ad1a20dd082ae9ec18bcNicolas Prevot        markUserSetupComplete(context, UserHandle.myUserId());
313bf793102707971d77950ad1a20dd082ae9ec18bcNicolas Prevot    }
314bf793102707971d77950ad1a20dd082ae9ec18bcNicolas Prevot
31572023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz    /**
31672023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     * Sets user setup complete on a given user.
31772023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     *
31872023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     * <p>This will set USER_SETUP_COMPLETE to 1 on the given user.
31972023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     */
32072023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz    public void markUserSetupComplete(Context context, int userId) {
321a7c379a97ce785b918a10c137e636d63a8d50010Alan Treadway        ProvisionLogger.logd("Setting USER_SETUP_COMPLETE to 1 for user " + userId);
322bf793102707971d77950ad1a20dd082ae9ec18bcNicolas Prevot        Secure.putIntForUser(context.getContentResolver(), Secure.USER_SETUP_COMPLETE, 1, userId);
323a5daf2dfdbb7c1b1ea5b930cc7836cf67778dde4Sudheer Shanka    }
324a5daf2dfdbb7c1b1ea5b930cc7836cf67778dde4Sudheer Shanka
32572023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz    /**
32672023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     * Returns whether USER_SETUP_COMPLETE is set on the calling user.
32772023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     */
32872023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz    public boolean isUserSetupCompleted(Context context) {
329a5daf2dfdbb7c1b1ea5b930cc7836cf67778dde4Sudheer Shanka        return Secure.getInt(context.getContentResolver(), Secure.USER_SETUP_COMPLETE, 0) != 0;
330a5daf2dfdbb7c1b1ea5b930cc7836cf67778dde4Sudheer Shanka    }
331a5daf2dfdbb7c1b1ea5b930cc7836cf67778dde4Sudheer Shanka
332ba113214d1820f32e5132cd83a06fa1eaedd2866Alan Treadway    /**
333ba113214d1820f32e5132cd83a06fa1eaedd2866Alan Treadway     * Set the current users userProvisioningState depending on the following factors:
334ba113214d1820f32e5132cd83a06fa1eaedd2866Alan Treadway     * <ul>
335ba113214d1820f32e5132cd83a06fa1eaedd2866Alan Treadway     *     <li>We're setting up a managed-profile - need to set state on two users.</li>
336ba113214d1820f32e5132cd83a06fa1eaedd2866Alan Treadway     *     <li>User-setup is complete or not - skip states relating to communicating with
337ba113214d1820f32e5132cd83a06fa1eaedd2866Alan Treadway     *     setup-wizard</li>
338ba113214d1820f32e5132cd83a06fa1eaedd2866Alan Treadway     *     <li>DPC requested we skip the rest of setup-wizard.</li>
339ba113214d1820f32e5132cd83a06fa1eaedd2866Alan Treadway     * </ul>
340ba113214d1820f32e5132cd83a06fa1eaedd2866Alan Treadway     *
34172023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     * @param context a {@link Context} object
342ba113214d1820f32e5132cd83a06fa1eaedd2866Alan Treadway     * @param params configuration for current provisioning attempt
343ba113214d1820f32e5132cd83a06fa1eaedd2866Alan Treadway     */
34472023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz    // ToDo: Add unit tests
34572023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz    public void markUserProvisioningStateInitiallyDone(Context context,
346ba113214d1820f32e5132cd83a06fa1eaedd2866Alan Treadway            ProvisioningParams params) {
347ba113214d1820f32e5132cd83a06fa1eaedd2866Alan Treadway        int currentUserId = UserHandle.myUserId();
348ba113214d1820f32e5132cd83a06fa1eaedd2866Alan Treadway        int managedProfileUserId = -1;
349ba113214d1820f32e5132cd83a06fa1eaedd2866Alan Treadway        DevicePolicyManager dpm = context.getSystemService(DevicePolicyManager.class);
350ba113214d1820f32e5132cd83a06fa1eaedd2866Alan Treadway        Integer newState = null;
351ba113214d1820f32e5132cd83a06fa1eaedd2866Alan Treadway        Integer newProfileState = null;
352ba113214d1820f32e5132cd83a06fa1eaedd2866Alan Treadway
353ba113214d1820f32e5132cd83a06fa1eaedd2866Alan Treadway        boolean userSetupCompleted = isUserSetupCompleted(context);
354ba113214d1820f32e5132cd83a06fa1eaedd2866Alan Treadway        if (params.provisioningAction.equals(ACTION_PROVISION_MANAGED_PROFILE)) {
355ba113214d1820f32e5132cd83a06fa1eaedd2866Alan Treadway            // Managed profiles are a special case as two users are involved.
356ba113214d1820f32e5132cd83a06fa1eaedd2866Alan Treadway            managedProfileUserId = getManagedProfile(context).getIdentifier();
357ba113214d1820f32e5132cd83a06fa1eaedd2866Alan Treadway            if (userSetupCompleted) {
358ba113214d1820f32e5132cd83a06fa1eaedd2866Alan Treadway                // SUW on current user is complete, so nothing much to do beyond indicating we're
359ba113214d1820f32e5132cd83a06fa1eaedd2866Alan Treadway                // all done.
360ba113214d1820f32e5132cd83a06fa1eaedd2866Alan Treadway                newProfileState = DevicePolicyManager.STATE_USER_SETUP_FINALIZED;
361ba113214d1820f32e5132cd83a06fa1eaedd2866Alan Treadway            } else {
362ba113214d1820f32e5132cd83a06fa1eaedd2866Alan Treadway                // We're still in SUW, so indicate that a managed-profile was setup on current user,
363ba113214d1820f32e5132cd83a06fa1eaedd2866Alan Treadway                // and that we're awaiting finalization on both.
364ba113214d1820f32e5132cd83a06fa1eaedd2866Alan Treadway                newState = DevicePolicyManager.STATE_USER_PROFILE_COMPLETE;
365ba113214d1820f32e5132cd83a06fa1eaedd2866Alan Treadway                newProfileState = DevicePolicyManager.STATE_USER_SETUP_COMPLETE;
366ba113214d1820f32e5132cd83a06fa1eaedd2866Alan Treadway            }
367ba113214d1820f32e5132cd83a06fa1eaedd2866Alan Treadway        } else if (userSetupCompleted) {
368ba113214d1820f32e5132cd83a06fa1eaedd2866Alan Treadway            // User setup was previously completed this is an unexpected case.
369ba113214d1820f32e5132cd83a06fa1eaedd2866Alan Treadway            ProvisionLogger.logw("user_setup_complete set, but provisioning was started");
370ba113214d1820f32e5132cd83a06fa1eaedd2866Alan Treadway        } else if (params.skipUserSetup) {
371ba113214d1820f32e5132cd83a06fa1eaedd2866Alan Treadway            // DPC requested setup-wizard is skipped, indicate this to SUW.
372ba113214d1820f32e5132cd83a06fa1eaedd2866Alan Treadway            newState = DevicePolicyManager.STATE_USER_SETUP_COMPLETE;
373ba113214d1820f32e5132cd83a06fa1eaedd2866Alan Treadway        } else {
374ba113214d1820f32e5132cd83a06fa1eaedd2866Alan Treadway            // DPC requested setup-wizard is not skipped, indicate this to SUW.
375ba113214d1820f32e5132cd83a06fa1eaedd2866Alan Treadway            newState = DevicePolicyManager.STATE_USER_SETUP_INCOMPLETE;
376ba113214d1820f32e5132cd83a06fa1eaedd2866Alan Treadway        }
377ba113214d1820f32e5132cd83a06fa1eaedd2866Alan Treadway
378ba113214d1820f32e5132cd83a06fa1eaedd2866Alan Treadway        if (newState != null) {
379ba113214d1820f32e5132cd83a06fa1eaedd2866Alan Treadway            setUserProvisioningState(dpm, newState, currentUserId);
380ba113214d1820f32e5132cd83a06fa1eaedd2866Alan Treadway        }
381ba113214d1820f32e5132cd83a06fa1eaedd2866Alan Treadway        if (newProfileState != null) {
382ba113214d1820f32e5132cd83a06fa1eaedd2866Alan Treadway            setUserProvisioningState(dpm, newProfileState, managedProfileUserId);
383ba113214d1820f32e5132cd83a06fa1eaedd2866Alan Treadway        }
384ba113214d1820f32e5132cd83a06fa1eaedd2866Alan Treadway        if (!userSetupCompleted) {
385ba113214d1820f32e5132cd83a06fa1eaedd2866Alan Treadway            // We expect a PROVISIONING_FINALIZATION intent to finish setup if we're still in
386ba113214d1820f32e5132cd83a06fa1eaedd2866Alan Treadway            // user-setup.
387ba113214d1820f32e5132cd83a06fa1eaedd2866Alan Treadway            FinalizationActivity.storeProvisioningParams(context, params);
388ba113214d1820f32e5132cd83a06fa1eaedd2866Alan Treadway        }
389ba113214d1820f32e5132cd83a06fa1eaedd2866Alan Treadway    }
390ba113214d1820f32e5132cd83a06fa1eaedd2866Alan Treadway
391ba113214d1820f32e5132cd83a06fa1eaedd2866Alan Treadway    /**
392ba113214d1820f32e5132cd83a06fa1eaedd2866Alan Treadway     * Finalize the current users userProvisioningState depending on the following factors:
393ba113214d1820f32e5132cd83a06fa1eaedd2866Alan Treadway     * <ul>
394ba113214d1820f32e5132cd83a06fa1eaedd2866Alan Treadway     *     <li>We're setting up a managed-profile - need to set state on two users.</li>
395ba113214d1820f32e5132cd83a06fa1eaedd2866Alan Treadway     * </ul>
396ba113214d1820f32e5132cd83a06fa1eaedd2866Alan Treadway     *
39772023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     * @param context a {@link Context} object
398ba113214d1820f32e5132cd83a06fa1eaedd2866Alan Treadway     * @param params configuration for current provisioning attempt - if null (because
399ba113214d1820f32e5132cd83a06fa1eaedd2866Alan Treadway     *               ManagedProvisioning wasn't used for first phase of provisioning) aassumes we
400ba113214d1820f32e5132cd83a06fa1eaedd2866Alan Treadway     *               can just mark current user as being in finalized provisioning state
401ba113214d1820f32e5132cd83a06fa1eaedd2866Alan Treadway     */
40272023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz    // ToDo: Add unit tests
40372023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz    public void markUserProvisioningStateFinalized(Context context,
404ba113214d1820f32e5132cd83a06fa1eaedd2866Alan Treadway            ProvisioningParams params) {
405ba113214d1820f32e5132cd83a06fa1eaedd2866Alan Treadway        int currentUserId = UserHandle.myUserId();
406ba113214d1820f32e5132cd83a06fa1eaedd2866Alan Treadway        int managedProfileUserId = -1;
407ba113214d1820f32e5132cd83a06fa1eaedd2866Alan Treadway        DevicePolicyManager dpm = context.getSystemService(DevicePolicyManager.class);
408ba113214d1820f32e5132cd83a06fa1eaedd2866Alan Treadway        Integer newState = null;
409ba113214d1820f32e5132cd83a06fa1eaedd2866Alan Treadway        Integer newProfileState = null;
410ba113214d1820f32e5132cd83a06fa1eaedd2866Alan Treadway
411ba113214d1820f32e5132cd83a06fa1eaedd2866Alan Treadway        if (params != null && params.provisioningAction.equals(ACTION_PROVISION_MANAGED_PROFILE)) {
412ba113214d1820f32e5132cd83a06fa1eaedd2866Alan Treadway            // Managed profiles are a special case as two users are involved.
413ba113214d1820f32e5132cd83a06fa1eaedd2866Alan Treadway            managedProfileUserId = getManagedProfile(context).getIdentifier();
414ba113214d1820f32e5132cd83a06fa1eaedd2866Alan Treadway
415ba113214d1820f32e5132cd83a06fa1eaedd2866Alan Treadway            newState = DevicePolicyManager.STATE_USER_UNMANAGED;
416ba113214d1820f32e5132cd83a06fa1eaedd2866Alan Treadway            newProfileState = DevicePolicyManager.STATE_USER_SETUP_FINALIZED;
417ba113214d1820f32e5132cd83a06fa1eaedd2866Alan Treadway        } else {
418ba113214d1820f32e5132cd83a06fa1eaedd2866Alan Treadway            newState = DevicePolicyManager.STATE_USER_SETUP_FINALIZED;
419ba113214d1820f32e5132cd83a06fa1eaedd2866Alan Treadway        }
420ba113214d1820f32e5132cd83a06fa1eaedd2866Alan Treadway
421ba113214d1820f32e5132cd83a06fa1eaedd2866Alan Treadway        if (newState != null) {
422ba113214d1820f32e5132cd83a06fa1eaedd2866Alan Treadway            setUserProvisioningState(dpm, newState, currentUserId);
423ba113214d1820f32e5132cd83a06fa1eaedd2866Alan Treadway        }
424ba113214d1820f32e5132cd83a06fa1eaedd2866Alan Treadway        if (newProfileState != null) {
425ba113214d1820f32e5132cd83a06fa1eaedd2866Alan Treadway            setUserProvisioningState(dpm, newProfileState, managedProfileUserId);
426ba113214d1820f32e5132cd83a06fa1eaedd2866Alan Treadway        }
427ba113214d1820f32e5132cd83a06fa1eaedd2866Alan Treadway    }
428ba113214d1820f32e5132cd83a06fa1eaedd2866Alan Treadway
42972023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz    private void setUserProvisioningState(DevicePolicyManager dpm, int state, int userId) {
430ba113214d1820f32e5132cd83a06fa1eaedd2866Alan Treadway        ProvisionLogger.logi("Setting userProvisioningState for user " + userId + " to: " + state);
431ba113214d1820f32e5132cd83a06fa1eaedd2866Alan Treadway        dpm.setUserProvisioningState(state, userId);
432ba113214d1820f32e5132cd83a06fa1eaedd2866Alan Treadway    }
433ba113214d1820f32e5132cd83a06fa1eaedd2866Alan Treadway
43472023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz    /**
43572023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     * Returns the first existing managed profile if any present, null otherwise.
43672023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     *
43772023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     * <p>Note that we currently only support one managed profile per device.
43872023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     */
43972023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz    // ToDo: Add unit tests
44072023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz    public UserHandle getManagedProfile(Context context) {
441a5daf2dfdbb7c1b1ea5b930cc7836cf67778dde4Sudheer Shanka        UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
442a5daf2dfdbb7c1b1ea5b930cc7836cf67778dde4Sudheer Shanka        int currentUserId = userManager.getUserHandle();
443a5daf2dfdbb7c1b1ea5b930cc7836cf67778dde4Sudheer Shanka        List<UserInfo> userProfiles = userManager.getProfiles(currentUserId);
444a5daf2dfdbb7c1b1ea5b930cc7836cf67778dde4Sudheer Shanka        for (UserInfo profile : userProfiles) {
445a5daf2dfdbb7c1b1ea5b930cc7836cf67778dde4Sudheer Shanka            if (profile.isManagedProfile()) {
446a5daf2dfdbb7c1b1ea5b930cc7836cf67778dde4Sudheer Shanka                return new UserHandle(profile.id);
447a5daf2dfdbb7c1b1ea5b930cc7836cf67778dde4Sudheer Shanka            }
448a5daf2dfdbb7c1b1ea5b930cc7836cf67778dde4Sudheer Shanka        }
449a5daf2dfdbb7c1b1ea5b930cc7836cf67778dde4Sudheer Shanka        return null;
450a5daf2dfdbb7c1b1ea5b930cc7836cf67778dde4Sudheer Shanka    }
451a5daf2dfdbb7c1b1ea5b930cc7836cf67778dde4Sudheer Shanka
452a5daf2dfdbb7c1b1ea5b930cc7836cf67778dde4Sudheer Shanka    /**
45372023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     * Returns the user id of an already existing managed profile or -1 if none exists.
454a5daf2dfdbb7c1b1ea5b930cc7836cf67778dde4Sudheer Shanka     */
45572023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz    // ToDo: Add unit tests
45672023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz    public int alreadyHasManagedProfile(Context context) {
457a5daf2dfdbb7c1b1ea5b930cc7836cf67778dde4Sudheer Shanka        UserHandle managedUser = getManagedProfile(context);
458a5daf2dfdbb7c1b1ea5b930cc7836cf67778dde4Sudheer Shanka        if (managedUser != null) {
459a5daf2dfdbb7c1b1ea5b930cc7836cf67778dde4Sudheer Shanka            return managedUser.getIdentifier();
460a5daf2dfdbb7c1b1ea5b930cc7836cf67778dde4Sudheer Shanka        } else {
461a5daf2dfdbb7c1b1ea5b930cc7836cf67778dde4Sudheer Shanka            return -1;
462a5daf2dfdbb7c1b1ea5b930cc7836cf67778dde4Sudheer Shanka        }
463a5daf2dfdbb7c1b1ea5b930cc7836cf67778dde4Sudheer Shanka    }
464a5daf2dfdbb7c1b1ea5b930cc7836cf67778dde4Sudheer Shanka
46572023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz    /**
46672023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     * Removes an account.
46772023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     *
46872023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     * <p>This removes the given account from the calling user's list of accounts.
46972023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     *
47072023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     * @param context a {@link Context} object
47172023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     * @param account the account to be removed
47272023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     */
47372023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz    // ToDo: Add unit tests
47472023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz    public void removeAccount(Context context, Account account) {
475a5daf2dfdbb7c1b1ea5b930cc7836cf67778dde4Sudheer Shanka        try {
476a5daf2dfdbb7c1b1ea5b930cc7836cf67778dde4Sudheer Shanka            AccountManager accountManager =
477a5daf2dfdbb7c1b1ea5b930cc7836cf67778dde4Sudheer Shanka                    (AccountManager) context.getSystemService(Context.ACCOUNT_SERVICE);
478a5daf2dfdbb7c1b1ea5b930cc7836cf67778dde4Sudheer Shanka            AccountManagerFuture<Bundle> bundle = accountManager.removeAccount(account,
479a5daf2dfdbb7c1b1ea5b930cc7836cf67778dde4Sudheer Shanka                    null, null /* callback */, null /* handler */);
480a5daf2dfdbb7c1b1ea5b930cc7836cf67778dde4Sudheer Shanka            // Block to get the result of the removeAccount operation
481a5daf2dfdbb7c1b1ea5b930cc7836cf67778dde4Sudheer Shanka            if (bundle.getResult().getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false)) {
482a5daf2dfdbb7c1b1ea5b930cc7836cf67778dde4Sudheer Shanka                ProvisionLogger.logw("Account removed from the primary user.");
483a5daf2dfdbb7c1b1ea5b930cc7836cf67778dde4Sudheer Shanka            } else {
484a5daf2dfdbb7c1b1ea5b930cc7836cf67778dde4Sudheer Shanka                Intent removeIntent = (Intent) bundle.getResult().getParcelable(
485a5daf2dfdbb7c1b1ea5b930cc7836cf67778dde4Sudheer Shanka                        AccountManager.KEY_INTENT);
486a5daf2dfdbb7c1b1ea5b930cc7836cf67778dde4Sudheer Shanka                if (removeIntent != null) {
487a5daf2dfdbb7c1b1ea5b930cc7836cf67778dde4Sudheer Shanka                    ProvisionLogger.logi("Starting activity to remove account");
4880ed8f62fcb0c35402ccee0b93679ace2dc96a03bRubin Xu                    TrampolineActivity.startActivity(context, removeIntent);
489a5daf2dfdbb7c1b1ea5b930cc7836cf67778dde4Sudheer Shanka                } else {
490a5daf2dfdbb7c1b1ea5b930cc7836cf67778dde4Sudheer Shanka                    ProvisionLogger.logw("Could not remove account from the primary user.");
491a5daf2dfdbb7c1b1ea5b930cc7836cf67778dde4Sudheer Shanka                }
492a5daf2dfdbb7c1b1ea5b930cc7836cf67778dde4Sudheer Shanka            }
493a5daf2dfdbb7c1b1ea5b930cc7836cf67778dde4Sudheer Shanka        } catch (OperationCanceledException | AuthenticatorException | IOException e) {
494a5daf2dfdbb7c1b1ea5b930cc7836cf67778dde4Sudheer Shanka            ProvisionLogger.logw("Exception removing account from the primary user.", e);
495a5daf2dfdbb7c1b1ea5b930cc7836cf67778dde4Sudheer Shanka        }
496a5daf2dfdbb7c1b1ea5b930cc7836cf67778dde4Sudheer Shanka    }
4976f4ef25d4d1c3473b293e1de7f07dbbc55dc4616Rubin Xu
49872023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz    /**
49972023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     * Copies an account to a given user.
50072023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     *
50172023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     * <p>Copies a given account form {@code sourceUser} to {@code targetUser}. This call is
50272023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     * blocking until the operation has succeeded. If within a timeout the account hasn't been
50372023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     * successfully copied to the new user, we give up.
50472023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     *
50572023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     * @param context a {@link Context} object
50672023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     * @param accountToMigrate the account to be migrated
50772023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     * @param sourceUser the {@link UserHandle} of the user to copy from
50872023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     * @param targetUser the {@link UserHandle} of the user to copy to
50972023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     * @return whether account migration successfully completed
51072023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     */
51172023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz    public boolean maybeCopyAccount(Context context, Account accountToMigrate,
512ca9c867e27a1af69960c6c91d90177ea45c78d09Alan Treadway            UserHandle sourceUser, UserHandle targetUser) {
513ca9c867e27a1af69960c6c91d90177ea45c78d09Alan Treadway        if (accountToMigrate == null) {
514ca9c867e27a1af69960c6c91d90177ea45c78d09Alan Treadway            ProvisionLogger.logd("No account to migrate.");
51572023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz            return false;
516ca9c867e27a1af69960c6c91d90177ea45c78d09Alan Treadway        }
517ca9c867e27a1af69960c6c91d90177ea45c78d09Alan Treadway        if (sourceUser.equals(targetUser)) {
518ca9c867e27a1af69960c6c91d90177ea45c78d09Alan Treadway            ProvisionLogger.logw("sourceUser and targetUser are the same, won't migrate account.");
51972023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz            return false;
520ca9c867e27a1af69960c6c91d90177ea45c78d09Alan Treadway        }
521ca9c867e27a1af69960c6c91d90177ea45c78d09Alan Treadway        ProvisionLogger.logd("Attempting to copy account from " + sourceUser + " to " + targetUser);
522ca9c867e27a1af69960c6c91d90177ea45c78d09Alan Treadway        try {
523ca9c867e27a1af69960c6c91d90177ea45c78d09Alan Treadway            AccountManager accountManager =
524ca9c867e27a1af69960c6c91d90177ea45c78d09Alan Treadway                    (AccountManager) context.getSystemService(Context.ACCOUNT_SERVICE);
525ca9c867e27a1af69960c6c91d90177ea45c78d09Alan Treadway            boolean copySucceeded = accountManager.copyAccountToUser(
526ca9c867e27a1af69960c6c91d90177ea45c78d09Alan Treadway                    accountToMigrate,
527ca9c867e27a1af69960c6c91d90177ea45c78d09Alan Treadway                    sourceUser,
528ca9c867e27a1af69960c6c91d90177ea45c78d09Alan Treadway                    targetUser,
529ca9c867e27a1af69960c6c91d90177ea45c78d09Alan Treadway                    /* callback= */ null, /* handler= */ null)
530ca9c867e27a1af69960c6c91d90177ea45c78d09Alan Treadway                    .getResult(ACCOUNT_COPY_TIMEOUT_SECONDS, TimeUnit.SECONDS);
531ca9c867e27a1af69960c6c91d90177ea45c78d09Alan Treadway            if (copySucceeded) {
532ca9c867e27a1af69960c6c91d90177ea45c78d09Alan Treadway                ProvisionLogger.logi("Copied account to " + targetUser);
53372023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz                return true;
534ca9c867e27a1af69960c6c91d90177ea45c78d09Alan Treadway            } else {
535ca9c867e27a1af69960c6c91d90177ea45c78d09Alan Treadway                ProvisionLogger.loge("Could not copy account to " + targetUser);
536ca9c867e27a1af69960c6c91d90177ea45c78d09Alan Treadway            }
537ca9c867e27a1af69960c6c91d90177ea45c78d09Alan Treadway        } catch (OperationCanceledException | AuthenticatorException | IOException e) {
538ca9c867e27a1af69960c6c91d90177ea45c78d09Alan Treadway            ProvisionLogger.loge("Exception copying account to " + targetUser, e);
539ca9c867e27a1af69960c6c91d90177ea45c78d09Alan Treadway        }
54072023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz        return false;
541ca9c867e27a1af69960c6c91d90177ea45c78d09Alan Treadway    }
542ca9c867e27a1af69960c6c91d90177ea45c78d09Alan Treadway
54372023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz    /**
54472023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     * Returns whether FRP is supported on the device.
54572023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     */
54672023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz    public boolean isFrpSupported(Context context) {
5476f4ef25d4d1c3473b293e1de7f07dbbc55dc4616Rubin Xu        Object pdbManager = context.getSystemService(Context.PERSISTENT_DATA_BLOCK_SERVICE);
5486f4ef25d4d1c3473b293e1de7f07dbbc55dc4616Rubin Xu        return pdbManager != null;
5496f4ef25d4d1c3473b293e1de7f07dbbc55dc4616Rubin Xu    }
5506f4ef25d4d1c3473b293e1de7f07dbbc55dc4616Rubin Xu
5513128ba4542f3c4c90790af0564e75950c8900961Alan Treadway    /**
552eee36899e6a73cf7635b11bb1723a411f324ea91Steven Ng     * Translates a given managed provisioning intent to its corresponding provisioning flow, using
553eee36899e6a73cf7635b11bb1723a411f324ea91Steven Ng     * the action from the intent.
554eee36899e6a73cf7635b11bb1723a411f324ea91Steven Ng     *
555eee36899e6a73cf7635b11bb1723a411f324ea91Steven Ng     * <p/>This is necessary because, unlike other provisioning actions which has 1:1 mapping, there
556eee36899e6a73cf7635b11bb1723a411f324ea91Steven Ng     * are multiple actions that can trigger the device owner provisioning flow. This includes
557eee36899e6a73cf7635b11bb1723a411f324ea91Steven Ng     * {@link ACTION_PROVISION_MANAGED_DEVICE}, {@link ACTION_NDEF_DISCOVERED} and
558eee36899e6a73cf7635b11bb1723a411f324ea91Steven Ng     * {@link ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE}. These 3 actions are equivalent
559eee36899e6a73cf7635b11bb1723a411f324ea91Steven Ng     * excepts they are sent from a different source.
560eee36899e6a73cf7635b11bb1723a411f324ea91Steven Ng     *
561eee36899e6a73cf7635b11bb1723a411f324ea91Steven Ng     * @return the appropriate DevicePolicyManager declared action for the given incoming intent.
5623128ba4542f3c4c90790af0564e75950c8900961Alan Treadway     * @throws IllegalProvisioningArgumentException if intent is malformed
5633128ba4542f3c4c90790af0564e75950c8900961Alan Treadway     */
56472023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz    // ToDo: Add unit tests
56572023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz    public String mapIntentToDpmAction(Intent intent)
5663128ba4542f3c4c90790af0564e75950c8900961Alan Treadway            throws IllegalProvisioningArgumentException {
5673128ba4542f3c4c90790af0564e75950c8900961Alan Treadway        if (intent == null || intent.getAction() == null) {
5683128ba4542f3c4c90790af0564e75950c8900961Alan Treadway            throw new IllegalProvisioningArgumentException("Null intent action.");
5693128ba4542f3c4c90790af0564e75950c8900961Alan Treadway        }
5703128ba4542f3c4c90790af0564e75950c8900961Alan Treadway
5713128ba4542f3c4c90790af0564e75950c8900961Alan Treadway        // Map the incoming intent to a DevicePolicyManager.ACTION_*, as there is a N:1 mapping in
5723128ba4542f3c4c90790af0564e75950c8900961Alan Treadway        // some cases.
5733128ba4542f3c4c90790af0564e75950c8900961Alan Treadway        String dpmProvisioningAction;
5743128ba4542f3c4c90790af0564e75950c8900961Alan Treadway        switch (intent.getAction()) {
5753128ba4542f3c4c90790af0564e75950c8900961Alan Treadway            // Trivial cases.
5763128ba4542f3c4c90790af0564e75950c8900961Alan Treadway            case ACTION_PROVISION_MANAGED_DEVICE:
5773128ba4542f3c4c90790af0564e75950c8900961Alan Treadway            case ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE:
5783128ba4542f3c4c90790af0564e75950c8900961Alan Treadway            case ACTION_PROVISION_MANAGED_USER:
5793128ba4542f3c4c90790af0564e75950c8900961Alan Treadway            case ACTION_PROVISION_MANAGED_PROFILE:
5803128ba4542f3c4c90790af0564e75950c8900961Alan Treadway                dpmProvisioningAction = intent.getAction();
5813128ba4542f3c4c90790af0564e75950c8900961Alan Treadway                break;
5823128ba4542f3c4c90790af0564e75950c8900961Alan Treadway
5833128ba4542f3c4c90790af0564e75950c8900961Alan Treadway            // NFC cases which need to take mime-type into account.
5843128ba4542f3c4c90790af0564e75950c8900961Alan Treadway            case ACTION_NDEF_DISCOVERED:
5853128ba4542f3c4c90790af0564e75950c8900961Alan Treadway                String mimeType = intent.getType();
5863128ba4542f3c4c90790af0564e75950c8900961Alan Treadway                switch (mimeType) {
5873128ba4542f3c4c90790af0564e75950c8900961Alan Treadway                    case MIME_TYPE_PROVISIONING_NFC:
5883128ba4542f3c4c90790af0564e75950c8900961Alan Treadway                        dpmProvisioningAction = ACTION_PROVISION_MANAGED_DEVICE;
5893128ba4542f3c4c90790af0564e75950c8900961Alan Treadway                        break;
5903128ba4542f3c4c90790af0564e75950c8900961Alan Treadway
5913128ba4542f3c4c90790af0564e75950c8900961Alan Treadway                    default:
5923128ba4542f3c4c90790af0564e75950c8900961Alan Treadway                        throw new IllegalProvisioningArgumentException(
5933128ba4542f3c4c90790af0564e75950c8900961Alan Treadway                                "Unknown NFC bump mime-type: " + mimeType);
5943128ba4542f3c4c90790af0564e75950c8900961Alan Treadway                }
5953128ba4542f3c4c90790af0564e75950c8900961Alan Treadway                break;
5963128ba4542f3c4c90790af0564e75950c8900961Alan Treadway
597eee36899e6a73cf7635b11bb1723a411f324ea91Steven Ng            // Device owner provisioning from a trusted app.
598eee36899e6a73cf7635b11bb1723a411f324ea91Steven Ng            // TODO (b/27217042): review for new management modes in split system-user model
599eee36899e6a73cf7635b11bb1723a411f324ea91Steven Ng            case ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE:
600eee36899e6a73cf7635b11bb1723a411f324ea91Steven Ng                dpmProvisioningAction = ACTION_PROVISION_MANAGED_DEVICE;
601eee36899e6a73cf7635b11bb1723a411f324ea91Steven Ng                break;
602eee36899e6a73cf7635b11bb1723a411f324ea91Steven Ng
6033128ba4542f3c4c90790af0564e75950c8900961Alan Treadway            default:
6043128ba4542f3c4c90790af0564e75950c8900961Alan Treadway                throw new IllegalProvisioningArgumentException("Unknown intent action "
6053128ba4542f3c4c90790af0564e75950c8900961Alan Treadway                        + intent.getAction());
6063128ba4542f3c4c90790af0564e75950c8900961Alan Treadway        }
6073128ba4542f3c4c90790af0564e75950c8900961Alan Treadway        return dpmProvisioningAction;
6083128ba4542f3c4c90790af0564e75950c8900961Alan Treadway    }
6093128ba4542f3c4c90790af0564e75950c8900961Alan Treadway
6103128ba4542f3c4c90790af0564e75950c8900961Alan Treadway    /**
6113128ba4542f3c4c90790af0564e75950c8900961Alan Treadway     * @return the first {@link NdefRecord} found with a recognized MIME-type
6123128ba4542f3c4c90790af0564e75950c8900961Alan Treadway     */
61372023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz    // ToDo: Add unit tests
61472023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz    public NdefRecord firstNdefRecord(Intent nfcIntent) {
6153128ba4542f3c4c90790af0564e75950c8900961Alan Treadway        // Only one first message with NFC_MIME_TYPE is used.
6163128ba4542f3c4c90790af0564e75950c8900961Alan Treadway        for (Parcelable rawMsg : nfcIntent.getParcelableArrayExtra(
6173128ba4542f3c4c90790af0564e75950c8900961Alan Treadway                NfcAdapter.EXTRA_NDEF_MESSAGES)) {
6183128ba4542f3c4c90790af0564e75950c8900961Alan Treadway            NdefMessage msg = (NdefMessage) rawMsg;
6193128ba4542f3c4c90790af0564e75950c8900961Alan Treadway            for (NdefRecord record : msg.getRecords()) {
6203128ba4542f3c4c90790af0564e75950c8900961Alan Treadway                String mimeType = new String(record.getType(), UTF_8);
6213128ba4542f3c4c90790af0564e75950c8900961Alan Treadway
6223128ba4542f3c4c90790af0564e75950c8900961Alan Treadway                if (MIME_TYPE_PROVISIONING_NFC.equals(mimeType)) {
6233128ba4542f3c4c90790af0564e75950c8900961Alan Treadway                    return record;
6243128ba4542f3c4c90790af0564e75950c8900961Alan Treadway                }
6253128ba4542f3c4c90790af0564e75950c8900961Alan Treadway
6263128ba4542f3c4c90790af0564e75950c8900961Alan Treadway                // Assume only first record of message is used.
6273128ba4542f3c4c90790af0564e75950c8900961Alan Treadway                break;
6283128ba4542f3c4c90790af0564e75950c8900961Alan Treadway            }
6293128ba4542f3c4c90790af0564e75950c8900961Alan Treadway        }
6303128ba4542f3c4c90790af0564e75950c8900961Alan Treadway        return null;
6313128ba4542f3c4c90790af0564e75950c8900961Alan Treadway    }
632aa435a10268c541f7bd61a0a254ab934e48fc875Sudheer Shanka
63372023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz    /**
63472023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     * Sends an intent to trigger a factory reset.
63572023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     */
63672023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz    // ToDo: Move the FR intent into a Globals class.
63772023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz    public void sendFactoryResetBroadcast(Context context, String reason) {
638aa435a10268c541f7bd61a0a254ab934e48fc875Sudheer Shanka        Intent intent = new Intent(Intent.ACTION_MASTER_CLEAR);
639aa435a10268c541f7bd61a0a254ab934e48fc875Sudheer Shanka        intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
640aa435a10268c541f7bd61a0a254ab934e48fc875Sudheer Shanka        intent.putExtra(Intent.EXTRA_REASON, reason);
641aa435a10268c541f7bd61a0a254ab934e48fc875Sudheer Shanka        context.sendBroadcast(intent);
642aa435a10268c541f7bd61a0a254ab934e48fc875Sudheer Shanka    }
643e35cc9733194b380637728d39c14dcfc0adee84bNicolas Prevot
64472023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz    /**
64572023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     * Returns whether the given provisioning action is a profile owner action.
64672023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     */
64772023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz    // ToDo: Move the list of device owner actions into a Globals class.
64872023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz    public boolean isProfileOwnerAction(String action) {
649e35cc9733194b380637728d39c14dcfc0adee84bNicolas Prevot        return action.equals(ACTION_PROVISION_MANAGED_PROFILE)
650e35cc9733194b380637728d39c14dcfc0adee84bNicolas Prevot                || action.equals(ACTION_PROVISION_MANAGED_USER);
651e35cc9733194b380637728d39c14dcfc0adee84bNicolas Prevot    }
652e35cc9733194b380637728d39c14dcfc0adee84bNicolas Prevot
65372023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz    /**
65472023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     * Returns whether the given provisioning action is a device owner action.
65572023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     */
65672023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz    // ToDo: Move the list of device owner actions into a Globals class.
65772023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz    public boolean isDeviceOwnerAction(String action) {
658e35cc9733194b380637728d39c14dcfc0adee84bNicolas Prevot        return action.equals(ACTION_PROVISION_MANAGED_DEVICE)
659e35cc9733194b380637728d39c14dcfc0adee84bNicolas Prevot                || action.equals(ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE);
660e35cc9733194b380637728d39c14dcfc0adee84bNicolas Prevot    }
661e35cc9733194b380637728d39c14dcfc0adee84bNicolas Prevot
662d5e4c42542dd96d8940912cc20dff20fa48da0d9Sander Alewijnse}
663