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 Treadway
273128ba4542f3c4c90790af0564e75950c8900961Alan Treadwayimport android.accounts.Account;
283128ba4542f3c4c90790af0564e75950c8900961Alan Treadwayimport android.accounts.AccountManager;
293128ba4542f3c4c90790af0564e75950c8900961Alan Treadwayimport android.accounts.AccountManagerFuture;
303128ba4542f3c4c90790af0564e75950c8900961Alan Treadwayimport android.accounts.AuthenticatorException;
313128ba4542f3c4c90790af0564e75950c8900961Alan Treadwayimport android.accounts.OperationCanceledException;
32945e609e967c33897df9e5f53b86e0eaa6e53e2eBenjamin Franzimport android.annotation.NonNull;
33945e609e967c33897df9e5f53b86e0eaa6e53e2eBenjamin Franzimport android.annotation.Nullable;
3484e56f5cfc1d45b3983dd553096182e774d8cb2cJoe Delfinoimport android.app.admin.DevicePolicyManager;
359a42f2b64dada715248aec7c898f983375a395eeAlan Treadwayimport android.content.ComponentName;
360b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevotimport android.content.Context;
379a42f2b64dada715248aec7c898f983375a395eeAlan Treadwayimport android.content.Intent;
380b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevotimport android.content.pm.ActivityInfo;
39d5e4c42542dd96d8940912cc20dff20fa48da0d9Sander Alewijnseimport android.content.pm.ApplicationInfo;
40d5e4c42542dd96d8940912cc20dff20fa48da0d9Sander Alewijnseimport android.content.pm.IPackageManager;
410b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevotimport android.content.pm.PackageInfo;
42d5e4c42542dd96d8940912cc20dff20fa48da0d9Sander Alewijnseimport android.content.pm.PackageManager;
430b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevotimport android.content.pm.PackageManager.NameNotFoundException;
44ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franzimport android.content.pm.ResolveInfo;
4584e56f5cfc1d45b3983dd553096182e774d8cb2cJoe Delfinoimport android.content.pm.UserInfo;
46b38680c8eebfaf0af71efaf042383d06a2a8350aNicolas Prevotimport android.graphics.Color;
47ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franzimport android.net.ConnectivityManager;
48ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franzimport android.net.NetworkInfo;
49ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franzimport android.net.wifi.WifiManager;
50ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franzimport android.os.Build;
51a5daf2dfdbb7c1b1ea5b930cc7836cf67778dde4Sudheer Shankaimport android.os.Bundle;
52d5e4c42542dd96d8940912cc20dff20fa48da0d9Sander Alewijnseimport android.os.RemoteException;
53d5e4c42542dd96d8940912cc20dff20fa48da0d9Sander Alewijnseimport android.os.ServiceManager;
54ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franzimport android.os.SystemProperties;
55d0f2928a28d38ce8344b7f15fbfec97aebec0db6Joe Delfinoimport android.os.UserHandle;
5684e56f5cfc1d45b3983dd553096182e774d8cb2cJoe Delfinoimport android.os.UserManager;
57fce5147b7dbf266e9724dfb494cca88524b06bf8Ricky Waiimport android.os.storage.StorageManager;
580b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevotimport android.text.TextUtils;
593fee5b87a1d3bbace3932937520b238d1b8923efBenjamin Franz
603fee5b87a1d3bbace3932937520b238d1b8923efBenjamin Franzimport com.android.internal.annotations.VisibleForTesting;
613fee5b87a1d3bbace3932937520b238d1b8923efBenjamin Franzimport com.android.managedprovisioning.TrampolineActivity;
623fee5b87a1d3bbace3932937520b238d1b8923efBenjamin Franzimport com.android.managedprovisioning.model.PackageDownloadInfo;
63d5e4c42542dd96d8940912cc20dff20fa48da0d9Sander Alewijnse
64974f02ac4952ba596665c71d1e71717cf8f6ef7aNicolas Prevotimport java.io.FileInputStream;
65a5daf2dfdbb7c1b1ea5b930cc7836cf67778dde4Sudheer Shankaimport java.io.IOException;
66974f02ac4952ba596665c71d1e71717cf8f6ef7aNicolas Prevotimport java.io.InputStream;
67974f02ac4952ba596665c71d1e71717cf8f6ef7aNicolas Prevotimport java.security.MessageDigest;
68974f02ac4952ba596665c71d1e71717cf8f6ef7aNicolas Prevotimport java.security.NoSuchAlgorithmException;
69d5e4c42542dd96d8940912cc20dff20fa48da0d9Sander Alewijnseimport java.util.HashSet;
709a42f2b64dada715248aec7c898f983375a395eeAlan Treadwayimport java.util.List;
71d5e4c42542dd96d8940912cc20dff20fa48da0d9Sander Alewijnseimport java.util.Set;
7272023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz
73d5e4c42542dd96d8940912cc20dff20fa48da0d9Sander Alewijnse/**
74d5e4c42542dd96d8940912cc20dff20fa48da0d9Sander Alewijnse * Class containing various auxiliary methods.
75d5e4c42542dd96d8940912cc20dff20fa48da0d9Sander Alewijnse */
76d5e4c42542dd96d8940912cc20dff20fa48da0d9Sander Alewijnsepublic class Utils {
77974f02ac4952ba596665c71d1e71717cf8f6ef7aNicolas Prevot    public static final String SHA256_TYPE = "SHA-256";
78974f02ac4952ba596665c71d1e71717cf8f6ef7aNicolas Prevot    public static final String SHA1_TYPE = "SHA-1";
79974f02ac4952ba596665c71d1e71717cf8f6ef7aNicolas Prevot
803cc3880a7d61101d439cf6c5fdd351e22fdc8f4fJakub Gielzak    // value chosen to match UX designs; when updating check status bar icon colors
813cc3880a7d61101d439cf6c5fdd351e22fdc8f4fJakub Gielzak    private static final int THRESHOLD_BRIGHT_COLOR = 190;
82b38680c8eebfaf0af71efaf042383d06a2a8350aNicolas Prevot
8372023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz    public Utils() {}
849a42f2b64dada715248aec7c898f983375a395eeAlan Treadway
8572023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz    /**
8672023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     * Returns the currently installed system apps on a given user.
8772023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     *
8872023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     * <p>Calls into the {@link IPackageManager} to retrieve all installed packages on the given
8972023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     * user and returns the package names of all system apps.
9072023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     *
9172023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     * @param ipm an {@link IPackageManager} object
9272023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     * @param userId the id of the user we are interested in
9372023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     */
9472023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz    public Set<String> getCurrentSystemApps(IPackageManager ipm, int userId) {
95d5e4c42542dd96d8940912cc20dff20fa48da0d9Sander Alewijnse        Set<String> apps = new HashSet<String>();
96d5e4c42542dd96d8940912cc20dff20fa48da0d9Sander Alewijnse        List<ApplicationInfo> aInfos = null;
97d5e4c42542dd96d8940912cc20dff20fa48da0d9Sander Alewijnse        try {
98d5e4c42542dd96d8940912cc20dff20fa48da0d9Sander Alewijnse            aInfos = ipm.getInstalledApplications(
99d5e4c42542dd96d8940912cc20dff20fa48da0d9Sander Alewijnse                    PackageManager.GET_UNINSTALLED_PACKAGES, userId).getList();
100d5e4c42542dd96d8940912cc20dff20fa48da0d9Sander Alewijnse        } catch (RemoteException neverThrown) {
101d5e4c42542dd96d8940912cc20dff20fa48da0d9Sander Alewijnse            ProvisionLogger.loge("This should not happen.", neverThrown);
102d5e4c42542dd96d8940912cc20dff20fa48da0d9Sander Alewijnse        }
103d5e4c42542dd96d8940912cc20dff20fa48da0d9Sander Alewijnse        for (ApplicationInfo aInfo : aInfos) {
104d5e4c42542dd96d8940912cc20dff20fa48da0d9Sander Alewijnse            if ((aInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
105d5e4c42542dd96d8940912cc20dff20fa48da0d9Sander Alewijnse                apps.add(aInfo.packageName);
106d5e4c42542dd96d8940912cc20dff20fa48da0d9Sander Alewijnse            }
107d5e4c42542dd96d8940912cc20dff20fa48da0d9Sander Alewijnse        }
108d5e4c42542dd96d8940912cc20dff20fa48da0d9Sander Alewijnse        return apps;
109d5e4c42542dd96d8940912cc20dff20fa48da0d9Sander Alewijnse    }
110d5e4c42542dd96d8940912cc20dff20fa48da0d9Sander Alewijnse
11172023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz    /**
11272023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     * Disables a given component in a given user.
11372023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     *
11472023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     * @param toDisable the component that should be disabled
11572023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     * @param userId the id of the user where the component should be disabled.
11672023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     */
11772023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz    public void disableComponent(ComponentName toDisable, int userId) {
1180a964a32b7e8e7b2207416530f8f4575e1cde46eBenjamin Franz        setComponentEnabledSetting(
1190a964a32b7e8e7b2207416530f8f4575e1cde46eBenjamin Franz                IPackageManager.Stub.asInterface(ServiceManager.getService("package")),
1200a964a32b7e8e7b2207416530f8f4575e1cde46eBenjamin Franz                toDisable,
1210a964a32b7e8e7b2207416530f8f4575e1cde46eBenjamin Franz                PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
1220a964a32b7e8e7b2207416530f8f4575e1cde46eBenjamin Franz                userId);
1230a964a32b7e8e7b2207416530f8f4575e1cde46eBenjamin Franz    }
1240a964a32b7e8e7b2207416530f8f4575e1cde46eBenjamin Franz
1250a964a32b7e8e7b2207416530f8f4575e1cde46eBenjamin Franz    /**
1260a964a32b7e8e7b2207416530f8f4575e1cde46eBenjamin Franz     * Enables a given component in a given user.
1270a964a32b7e8e7b2207416530f8f4575e1cde46eBenjamin Franz     *
1280a964a32b7e8e7b2207416530f8f4575e1cde46eBenjamin Franz     * @param toEnable the component that should be enabled
1290a964a32b7e8e7b2207416530f8f4575e1cde46eBenjamin Franz     * @param userId the id of the user where the component should be disabled.
1300a964a32b7e8e7b2207416530f8f4575e1cde46eBenjamin Franz     */
1310a964a32b7e8e7b2207416530f8f4575e1cde46eBenjamin Franz    public void enableComponent(ComponentName toEnable, int userId) {
1320a964a32b7e8e7b2207416530f8f4575e1cde46eBenjamin Franz        setComponentEnabledSetting(
1330a964a32b7e8e7b2207416530f8f4575e1cde46eBenjamin Franz                IPackageManager.Stub.asInterface(ServiceManager.getService("package")),
1340a964a32b7e8e7b2207416530f8f4575e1cde46eBenjamin Franz                toEnable,
1350a964a32b7e8e7b2207416530f8f4575e1cde46eBenjamin Franz                PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
1360a964a32b7e8e7b2207416530f8f4575e1cde46eBenjamin Franz                userId);
13772023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz    }
138d5e4c42542dd96d8940912cc20dff20fa48da0d9Sander Alewijnse
13972023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz    /**
14072023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     * Disables a given component in a given user.
14172023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     *
14272023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     * @param ipm an {@link IPackageManager} object
14372023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     * @param toDisable the component that should be disabled
14472023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     * @param userId the id of the user where the component should be disabled.
14572023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     */
1460a964a32b7e8e7b2207416530f8f4575e1cde46eBenjamin Franz    @VisibleForTesting
1470a964a32b7e8e7b2207416530f8f4575e1cde46eBenjamin Franz    void setComponentEnabledSetting(IPackageManager ipm, ComponentName toDisable,
1480a964a32b7e8e7b2207416530f8f4575e1cde46eBenjamin Franz            int enabledSetting, int userId) {
14972023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz        try {
150d5e4c42542dd96d8940912cc20dff20fa48da0d9Sander Alewijnse            ipm.setComponentEnabledSetting(toDisable,
1510a964a32b7e8e7b2207416530f8f4575e1cde46eBenjamin Franz                    enabledSetting, PackageManager.DONT_KILL_APP,
152d5e4c42542dd96d8940912cc20dff20fa48da0d9Sander Alewijnse                    userId);
153d5e4c42542dd96d8940912cc20dff20fa48da0d9Sander Alewijnse        } catch (RemoteException neverThrown) {
154d5e4c42542dd96d8940912cc20dff20fa48da0d9Sander Alewijnse            ProvisionLogger.loge("This should not happen.", neverThrown);
155d5e4c42542dd96d8940912cc20dff20fa48da0d9Sander Alewijnse        } catch (Exception e) {
1560a964a32b7e8e7b2207416530f8f4575e1cde46eBenjamin Franz            ProvisionLogger.logw("Component not found, not changing enabled setting: "
157d5e4c42542dd96d8940912cc20dff20fa48da0d9Sander Alewijnse                + toDisable.toShortString());
158d5e4c42542dd96d8940912cc20dff20fa48da0d9Sander Alewijnse        }
159d5e4c42542dd96d8940912cc20dff20fa48da0d9Sander Alewijnse    }
1600b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevot
1610b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevot    /**
1620b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevot     * Check the validity of the admin component name supplied, or try to infer this componentName
1630b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevot     * from the package.
1640b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevot     *
1650b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevot     * We are supporting lookup by package name for legacy reasons.
1660b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevot     *
167945e609e967c33897df9e5f53b86e0eaa6e53e2eBenjamin Franz     * If dpcComponentName is supplied (not null): dpcPackageName is ignored.
168945e609e967c33897df9e5f53b86e0eaa6e53e2eBenjamin Franz     * Check that the package of dpcComponentName is installed, that dpcComponentName is a
169a1db3cc833895803213b1dab55b917ad8ab0359fTony Mak     * receiver in this package, and return it. The receiver can be in disabled state.
1700b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevot     *
171945e609e967c33897df9e5f53b86e0eaa6e53e2eBenjamin Franz     * Otherwise: dpcPackageName must be supplied (not null).
1720b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevot     * Check that this package is installed, try to infer a potential device admin in this package,
1730b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevot     * and return it.
1740b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevot     */
175945e609e967c33897df9e5f53b86e0eaa6e53e2eBenjamin Franz    @NonNull
176945e609e967c33897df9e5f53b86e0eaa6e53e2eBenjamin Franz    public ComponentName findDeviceAdmin(String dpcPackageName, ComponentName dpcComponentName,
177945e609e967c33897df9e5f53b86e0eaa6e53e2eBenjamin Franz            Context context) throws IllegalProvisioningArgumentException {
178945e609e967c33897df9e5f53b86e0eaa6e53e2eBenjamin Franz        if (dpcComponentName != null) {
179945e609e967c33897df9e5f53b86e0eaa6e53e2eBenjamin Franz            dpcPackageName = dpcComponentName.getPackageName();
1800b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevot        }
181945e609e967c33897df9e5f53b86e0eaa6e53e2eBenjamin Franz        if (dpcPackageName == null) {
1820b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevot            throw new IllegalProvisioningArgumentException("Neither the package name nor the"
1830b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevot                    + " component name of the admin are supplied");
1840b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevot        }
1850b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevot        PackageInfo pi;
1860b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevot        try {
187945e609e967c33897df9e5f53b86e0eaa6e53e2eBenjamin Franz            pi = context.getPackageManager().getPackageInfo(dpcPackageName,
188a1db3cc833895803213b1dab55b917ad8ab0359fTony Mak                    PackageManager.GET_RECEIVERS | PackageManager.MATCH_DISABLED_COMPONENTS);
1890b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevot        } catch (NameNotFoundException e) {
190945e609e967c33897df9e5f53b86e0eaa6e53e2eBenjamin Franz            throw new IllegalProvisioningArgumentException("Dpc "+ dpcPackageName
1910b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevot                    + " is not installed. ", e);
1920b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevot        }
193945e609e967c33897df9e5f53b86e0eaa6e53e2eBenjamin Franz
194be71433cf40426a420be70cd6388b198403e423dVictor Chang        final ComponentName componentName = findDeviceAdminInPackageInfo(dpcPackageName,
195be71433cf40426a420be70cd6388b198403e423dVictor Chang                dpcComponentName, pi);
196be71433cf40426a420be70cd6388b198403e423dVictor Chang        if (componentName == null) {
197be71433cf40426a420be70cd6388b198403e423dVictor Chang            throw new IllegalProvisioningArgumentException("Cannot find any admin receiver in "
198be71433cf40426a420be70cd6388b198403e423dVictor Chang                    + "package " + dpcPackageName + " with component " + dpcComponentName);
199be71433cf40426a420be70cd6388b198403e423dVictor Chang        }
200be71433cf40426a420be70cd6388b198403e423dVictor Chang        return componentName;
201be71433cf40426a420be70cd6388b198403e423dVictor Chang    }
202be71433cf40426a420be70cd6388b198403e423dVictor Chang
203be71433cf40426a420be70cd6388b198403e423dVictor Chang    /**
204be71433cf40426a420be70cd6388b198403e423dVictor Chang     * If dpcComponentName is not null: dpcPackageName is ignored.
205be71433cf40426a420be70cd6388b198403e423dVictor Chang     * Check that the package of dpcComponentName is installed, that dpcComponentName is a
206be71433cf40426a420be70cd6388b198403e423dVictor Chang     * receiver in this package, and return it. The receiver can be in disabled state.
207be71433cf40426a420be70cd6388b198403e423dVictor Chang     *
208be71433cf40426a420be70cd6388b198403e423dVictor Chang     * Otherwise, try to infer a potential device admin component in this package info.
209be71433cf40426a420be70cd6388b198403e423dVictor Chang     *
210be71433cf40426a420be70cd6388b198403e423dVictor Chang     * @return infered device admin component in package info. Otherwise, null
211be71433cf40426a420be70cd6388b198403e423dVictor Chang     */
212be71433cf40426a420be70cd6388b198403e423dVictor Chang    @Nullable
213be71433cf40426a420be70cd6388b198403e423dVictor Chang    public ComponentName findDeviceAdminInPackageInfo(@NonNull String dpcPackageName,
214be71433cf40426a420be70cd6388b198403e423dVictor Chang            @Nullable ComponentName dpcComponentName, @NonNull PackageInfo pi) {
21580d4103fd2d75be562bfe81c558033c327b379e9Victor Chang        if (dpcComponentName != null) {
21680d4103fd2d75be562bfe81c558033c327b379e9Victor Chang            if (!isComponentInPackageInfo(dpcComponentName, pi)) {
217be71433cf40426a420be70cd6388b198403e423dVictor Chang                ProvisionLogger.logw("The component " + dpcComponentName + " isn't registered in "
218be71433cf40426a420be70cd6388b198403e423dVictor Chang                        + "the apk");
219be71433cf40426a420be70cd6388b198403e423dVictor Chang                return null;
22080d4103fd2d75be562bfe81c558033c327b379e9Victor Chang            }
221be71433cf40426a420be70cd6388b198403e423dVictor Chang            return dpcComponentName;
22280d4103fd2d75be562bfe81c558033c327b379e9Victor Chang        } else {
223be71433cf40426a420be70cd6388b198403e423dVictor Chang            return findDeviceAdminInPackage(dpcPackageName, pi);
2240b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevot        }
2250b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevot    }
2260b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevot
22772023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz    /**
228945e609e967c33897df9e5f53b86e0eaa6e53e2eBenjamin Franz     * Finds a device admin in a given {@link PackageInfo} object.
22972023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     *
230945e609e967c33897df9e5f53b86e0eaa6e53e2eBenjamin Franz     * <p>This function returns {@code null} if no or multiple admin receivers were found, and if
231945e609e967c33897df9e5f53b86e0eaa6e53e2eBenjamin Franz     * the package name does not match dpcPackageName.</p>
232945e609e967c33897df9e5f53b86e0eaa6e53e2eBenjamin Franz     * @param packageName packge name that should match the {@link PackageInfo} object.
233945e609e967c33897df9e5f53b86e0eaa6e53e2eBenjamin Franz     * @param packageInfo package info to be examined.
234945e609e967c33897df9e5f53b86e0eaa6e53e2eBenjamin Franz     * @return admin receiver or null in case of error.
23572023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     */
236945e609e967c33897df9e5f53b86e0eaa6e53e2eBenjamin Franz    @Nullable
237be71433cf40426a420be70cd6388b198403e423dVictor Chang    private ComponentName findDeviceAdminInPackage(String packageName, PackageInfo packageInfo) {
238945e609e967c33897df9e5f53b86e0eaa6e53e2eBenjamin Franz        if (packageInfo == null || !TextUtils.equals(packageInfo.packageName, packageName)) {
239945e609e967c33897df9e5f53b86e0eaa6e53e2eBenjamin Franz            return null;
2400b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevot        }
2410b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevot
2420b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevot        ComponentName mdmComponentName = null;
243945e609e967c33897df9e5f53b86e0eaa6e53e2eBenjamin Franz        for (ActivityInfo ai : packageInfo.receivers) {
244945e609e967c33897df9e5f53b86e0eaa6e53e2eBenjamin Franz            if (TextUtils.equals(ai.permission, android.Manifest.permission.BIND_DEVICE_ADMIN)) {
2450b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevot                if (mdmComponentName != null) {
246be71433cf40426a420be70cd6388b198403e423dVictor Chang                    ProvisionLogger.logw("more than 1 device admin component are found");
247945e609e967c33897df9e5f53b86e0eaa6e53e2eBenjamin Franz                    return null;
2480b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevot                } else {
249945e609e967c33897df9e5f53b86e0eaa6e53e2eBenjamin Franz                    mdmComponentName = new ComponentName(packageName, ai.name);
2500b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevot                }
2510b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevot            }
2520b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevot        }
2530b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevot        return mdmComponentName;
2540b4472570d93aeeda5a33dc05c0dcf03f2d3538bNicolas Prevot    }
2559a42f2b64dada715248aec7c898f983375a395eeAlan Treadway
25680d4103fd2d75be562bfe81c558033c327b379e9Victor Chang    private boolean isComponentInPackageInfo(ComponentName dpcComponentName,
25780d4103fd2d75be562bfe81c558033c327b379e9Victor Chang            PackageInfo pi) {
25880d4103fd2d75be562bfe81c558033c327b379e9Victor Chang        for (ActivityInfo ai : pi.receivers) {
25980d4103fd2d75be562bfe81c558033c327b379e9Victor Chang            if (dpcComponentName.getClassName().equals(ai.name)) {
26080d4103fd2d75be562bfe81c558033c327b379e9Victor Chang                return true;
26180d4103fd2d75be562bfe81c558033c327b379e9Victor Chang            }
26280d4103fd2d75be562bfe81c558033c327b379e9Victor Chang        }
26380d4103fd2d75be562bfe81c558033c327b379e9Victor Chang        return false;
26480d4103fd2d75be562bfe81c558033c327b379e9Victor Chang    }
26580d4103fd2d75be562bfe81c558033c327b379e9Victor Chang
2669a42f2b64dada715248aec7c898f983375a395eeAlan Treadway    /**
2672ecfc6315b527e62bd5a303cd726a4d7009f774aVictor Chang     * Return if a given package has testOnly="true", in which case we'll relax certain rules
2682ecfc6315b527e62bd5a303cd726a4d7009f774aVictor Chang     * for CTS.
2692ecfc6315b527e62bd5a303cd726a4d7009f774aVictor Chang     *
2702ecfc6315b527e62bd5a303cd726a4d7009f774aVictor Chang     * The system allows this flag to be changed when an app is updated. But
2712ecfc6315b527e62bd5a303cd726a4d7009f774aVictor Chang     * {@link DevicePolicyManager} uses the persisted version to do actual checks for relevant
2722ecfc6315b527e62bd5a303cd726a4d7009f774aVictor Chang     * dpm command.
2732ecfc6315b527e62bd5a303cd726a4d7009f774aVictor Chang     *
2742ecfc6315b527e62bd5a303cd726a4d7009f774aVictor Chang     * @see DevicePolicyManagerService#isPackageTestOnly for more info
2752ecfc6315b527e62bd5a303cd726a4d7009f774aVictor Chang     */
2762ecfc6315b527e62bd5a303cd726a4d7009f774aVictor Chang    public boolean isPackageTestOnly(PackageManager pm, String packageName, int userHandle) {
2772ecfc6315b527e62bd5a303cd726a4d7009f774aVictor Chang        if (TextUtils.isEmpty(packageName)) {
2782ecfc6315b527e62bd5a303cd726a4d7009f774aVictor Chang            return false;
2792ecfc6315b527e62bd5a303cd726a4d7009f774aVictor Chang        }
2802ecfc6315b527e62bd5a303cd726a4d7009f774aVictor Chang
2812ecfc6315b527e62bd5a303cd726a4d7009f774aVictor Chang        try {
2822ecfc6315b527e62bd5a303cd726a4d7009f774aVictor Chang            final ApplicationInfo ai = pm.getApplicationInfoAsUser(packageName,
2832ecfc6315b527e62bd5a303cd726a4d7009f774aVictor Chang                    PackageManager.MATCH_DIRECT_BOOT_AWARE
2842ecfc6315b527e62bd5a303cd726a4d7009f774aVictor Chang                            | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userHandle);
2852ecfc6315b527e62bd5a303cd726a4d7009f774aVictor Chang            return ai != null && (ai.flags & ApplicationInfo.FLAG_TEST_ONLY) != 0;
2862ecfc6315b527e62bd5a303cd726a4d7009f774aVictor Chang        } catch (PackageManager.NameNotFoundException e) {
2872ecfc6315b527e62bd5a303cd726a4d7009f774aVictor Chang            return false;
2882ecfc6315b527e62bd5a303cd726a4d7009f774aVictor Chang        }
2892ecfc6315b527e62bd5a303cd726a4d7009f774aVictor Chang
2902ecfc6315b527e62bd5a303cd726a4d7009f774aVictor Chang    }
2912ecfc6315b527e62bd5a303cd726a4d7009f774aVictor Chang
2922ecfc6315b527e62bd5a303cd726a4d7009f774aVictor Chang    /**
2932ecfc6315b527e62bd5a303cd726a4d7009f774aVictor Chang     * Returns whether the current user is the system user.
2942ecfc6315b527e62bd5a303cd726a4d7009f774aVictor Chang     */
2952ecfc6315b527e62bd5a303cd726a4d7009f774aVictor Chang    public boolean isCurrentUserSystem() {
2962ecfc6315b527e62bd5a303cd726a4d7009f774aVictor Chang        return UserHandle.myUserId() == UserHandle.USER_SYSTEM;
2972ecfc6315b527e62bd5a303cd726a4d7009f774aVictor Chang    }
2982ecfc6315b527e62bd5a303cd726a4d7009f774aVictor Chang
2992ecfc6315b527e62bd5a303cd726a4d7009f774aVictor Chang    /**
3002ecfc6315b527e62bd5a303cd726a4d7009f774aVictor Chang     * Returns whether the device is currently managed.
3012ecfc6315b527e62bd5a303cd726a4d7009f774aVictor Chang     */
3022ecfc6315b527e62bd5a303cd726a4d7009f774aVictor Chang    public boolean isDeviceManaged(Context context) {
3032ecfc6315b527e62bd5a303cd726a4d7009f774aVictor Chang        DevicePolicyManager dpm =
3042ecfc6315b527e62bd5a303cd726a4d7009f774aVictor Chang                (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE);
3052ecfc6315b527e62bd5a303cd726a4d7009f774aVictor Chang        return dpm.isDeviceManaged();
3062ecfc6315b527e62bd5a303cd726a4d7009f774aVictor Chang    }
3072ecfc6315b527e62bd5a303cd726a4d7009f774aVictor Chang
3082ecfc6315b527e62bd5a303cd726a4d7009f774aVictor Chang    /**
30972023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     * Returns true if the given package requires an update.
31072023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     *
31172023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     * <p>There are two cases where an update is required:
31272023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     * 1. The package is not currently present on the device.
31372023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     * 2. The package is present, but the version is below the minimum supported version.
31472023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     *
31572023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     * @param packageName the package to be checked for updates
31672023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     * @param minSupportedVersion the minimum supported version
31772023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     * @param context a {@link Context} object
31874d6c14da5117ffd3458602f9f6946c531143436Sander Alewijnse     */
31972023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz    public boolean packageRequiresUpdate(String packageName, int minSupportedVersion,
32074d6c14da5117ffd3458602f9f6946c531143436Sander Alewijnse            Context context) {
32174d6c14da5117ffd3458602f9f6946c531143436Sander Alewijnse        try {
32274d6c14da5117ffd3458602f9f6946c531143436Sander Alewijnse            PackageInfo packageInfo = context.getPackageManager().getPackageInfo(packageName, 0);
323d1784bd4d917bb36125e6faf125a2425c343838bSteven Ng            // Always download packages if no minimum version given.
324d1784bd4d917bb36125e6faf125a2425c343838bSteven Ng            if (minSupportedVersion != PackageDownloadInfo.DEFAULT_MINIMUM_VERSION
325d1784bd4d917bb36125e6faf125a2425c343838bSteven Ng                    && packageInfo.versionCode >= minSupportedVersion) {
32674d6c14da5117ffd3458602f9f6946c531143436Sander Alewijnse                return false;
32774d6c14da5117ffd3458602f9f6946c531143436Sander Alewijnse            }
32874d6c14da5117ffd3458602f9f6946c531143436Sander Alewijnse        } catch (NameNotFoundException e) {
32974d6c14da5117ffd3458602f9f6946c531143436Sander Alewijnse            // Package not on device.
33074d6c14da5117ffd3458602f9f6946c531143436Sander Alewijnse        }
33174d6c14da5117ffd3458602f9f6946c531143436Sander Alewijnse
33274d6c14da5117ffd3458602f9f6946c531143436Sander Alewijnse        return true;
33374d6c14da5117ffd3458602f9f6946c531143436Sander Alewijnse    }
33474d6c14da5117ffd3458602f9f6946c531143436Sander Alewijnse
33572023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz    /**
33672023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     * Returns the first existing managed profile if any present, null otherwise.
33772023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     *
33872023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     * <p>Note that we currently only support one managed profile per device.
33972023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     */
340ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franz    // TODO: Add unit tests
34172023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz    public UserHandle getManagedProfile(Context context) {
342a5daf2dfdbb7c1b1ea5b930cc7836cf67778dde4Sudheer Shanka        UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
343a5daf2dfdbb7c1b1ea5b930cc7836cf67778dde4Sudheer Shanka        int currentUserId = userManager.getUserHandle();
344a5daf2dfdbb7c1b1ea5b930cc7836cf67778dde4Sudheer Shanka        List<UserInfo> userProfiles = userManager.getProfiles(currentUserId);
345a5daf2dfdbb7c1b1ea5b930cc7836cf67778dde4Sudheer Shanka        for (UserInfo profile : userProfiles) {
346a5daf2dfdbb7c1b1ea5b930cc7836cf67778dde4Sudheer Shanka            if (profile.isManagedProfile()) {
347a5daf2dfdbb7c1b1ea5b930cc7836cf67778dde4Sudheer Shanka                return new UserHandle(profile.id);
348a5daf2dfdbb7c1b1ea5b930cc7836cf67778dde4Sudheer Shanka            }
349a5daf2dfdbb7c1b1ea5b930cc7836cf67778dde4Sudheer Shanka        }
350a5daf2dfdbb7c1b1ea5b930cc7836cf67778dde4Sudheer Shanka        return null;
351a5daf2dfdbb7c1b1ea5b930cc7836cf67778dde4Sudheer Shanka    }
352a5daf2dfdbb7c1b1ea5b930cc7836cf67778dde4Sudheer Shanka
353a5daf2dfdbb7c1b1ea5b930cc7836cf67778dde4Sudheer Shanka    /**
35472023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     * Returns the user id of an already existing managed profile or -1 if none exists.
355a5daf2dfdbb7c1b1ea5b930cc7836cf67778dde4Sudheer Shanka     */
356ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franz    // TODO: Add unit tests
35772023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz    public int alreadyHasManagedProfile(Context context) {
358a5daf2dfdbb7c1b1ea5b930cc7836cf67778dde4Sudheer Shanka        UserHandle managedUser = getManagedProfile(context);
359a5daf2dfdbb7c1b1ea5b930cc7836cf67778dde4Sudheer Shanka        if (managedUser != null) {
360a5daf2dfdbb7c1b1ea5b930cc7836cf67778dde4Sudheer Shanka            return managedUser.getIdentifier();
361a5daf2dfdbb7c1b1ea5b930cc7836cf67778dde4Sudheer Shanka        } else {
362a5daf2dfdbb7c1b1ea5b930cc7836cf67778dde4Sudheer Shanka            return -1;
363a5daf2dfdbb7c1b1ea5b930cc7836cf67778dde4Sudheer Shanka        }
364a5daf2dfdbb7c1b1ea5b930cc7836cf67778dde4Sudheer Shanka    }
365a5daf2dfdbb7c1b1ea5b930cc7836cf67778dde4Sudheer Shanka
36672023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz    /**
36772023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     * Removes an account.
36872023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     *
36972023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     * <p>This removes the given account from the calling user's list of accounts.
37072023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     *
37172023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     * @param context a {@link Context} object
37272023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     * @param account the account to be removed
37372023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     */
374ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franz    // TODO: Add unit tests
37572023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz    public void removeAccount(Context context, Account account) {
376a5daf2dfdbb7c1b1ea5b930cc7836cf67778dde4Sudheer Shanka        try {
377a5daf2dfdbb7c1b1ea5b930cc7836cf67778dde4Sudheer Shanka            AccountManager accountManager =
378a5daf2dfdbb7c1b1ea5b930cc7836cf67778dde4Sudheer Shanka                    (AccountManager) context.getSystemService(Context.ACCOUNT_SERVICE);
379a5daf2dfdbb7c1b1ea5b930cc7836cf67778dde4Sudheer Shanka            AccountManagerFuture<Bundle> bundle = accountManager.removeAccount(account,
380a5daf2dfdbb7c1b1ea5b930cc7836cf67778dde4Sudheer Shanka                    null, null /* callback */, null /* handler */);
381a5daf2dfdbb7c1b1ea5b930cc7836cf67778dde4Sudheer Shanka            // Block to get the result of the removeAccount operation
382a5daf2dfdbb7c1b1ea5b930cc7836cf67778dde4Sudheer Shanka            if (bundle.getResult().getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false)) {
383a5daf2dfdbb7c1b1ea5b930cc7836cf67778dde4Sudheer Shanka                ProvisionLogger.logw("Account removed from the primary user.");
384a5daf2dfdbb7c1b1ea5b930cc7836cf67778dde4Sudheer Shanka            } else {
385a5daf2dfdbb7c1b1ea5b930cc7836cf67778dde4Sudheer Shanka                Intent removeIntent = (Intent) bundle.getResult().getParcelable(
386a5daf2dfdbb7c1b1ea5b930cc7836cf67778dde4Sudheer Shanka                        AccountManager.KEY_INTENT);
387a5daf2dfdbb7c1b1ea5b930cc7836cf67778dde4Sudheer Shanka                if (removeIntent != null) {
388a5daf2dfdbb7c1b1ea5b930cc7836cf67778dde4Sudheer Shanka                    ProvisionLogger.logi("Starting activity to remove account");
3890ed8f62fcb0c35402ccee0b93679ace2dc96a03bRubin Xu                    TrampolineActivity.startActivity(context, removeIntent);
390a5daf2dfdbb7c1b1ea5b930cc7836cf67778dde4Sudheer Shanka                } else {
391a5daf2dfdbb7c1b1ea5b930cc7836cf67778dde4Sudheer Shanka                    ProvisionLogger.logw("Could not remove account from the primary user.");
392a5daf2dfdbb7c1b1ea5b930cc7836cf67778dde4Sudheer Shanka                }
393a5daf2dfdbb7c1b1ea5b930cc7836cf67778dde4Sudheer Shanka            }
394a5daf2dfdbb7c1b1ea5b930cc7836cf67778dde4Sudheer Shanka        } catch (OperationCanceledException | AuthenticatorException | IOException e) {
395a5daf2dfdbb7c1b1ea5b930cc7836cf67778dde4Sudheer Shanka            ProvisionLogger.logw("Exception removing account from the primary user.", e);
396a5daf2dfdbb7c1b1ea5b930cc7836cf67778dde4Sudheer Shanka        }
397a5daf2dfdbb7c1b1ea5b930cc7836cf67778dde4Sudheer Shanka    }
3986f4ef25d4d1c3473b293e1de7f07dbbc55dc4616Rubin Xu
39972023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz    /**
40072023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     * Returns whether FRP is supported on the device.
40172023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     */
40272023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz    public boolean isFrpSupported(Context context) {
4036f4ef25d4d1c3473b293e1de7f07dbbc55dc4616Rubin Xu        Object pdbManager = context.getSystemService(Context.PERSISTENT_DATA_BLOCK_SERVICE);
4046f4ef25d4d1c3473b293e1de7f07dbbc55dc4616Rubin Xu        return pdbManager != null;
4056f4ef25d4d1c3473b293e1de7f07dbbc55dc4616Rubin Xu    }
4066f4ef25d4d1c3473b293e1de7f07dbbc55dc4616Rubin Xu
4073128ba4542f3c4c90790af0564e75950c8900961Alan Treadway    /**
408eee36899e6a73cf7635b11bb1723a411f324ea91Steven Ng     * Translates a given managed provisioning intent to its corresponding provisioning flow, using
409eee36899e6a73cf7635b11bb1723a411f324ea91Steven Ng     * the action from the intent.
410eee36899e6a73cf7635b11bb1723a411f324ea91Steven Ng     *
411eee36899e6a73cf7635b11bb1723a411f324ea91Steven Ng     * <p/>This is necessary because, unlike other provisioning actions which has 1:1 mapping, there
412eee36899e6a73cf7635b11bb1723a411f324ea91Steven Ng     * are multiple actions that can trigger the device owner provisioning flow. This includes
413eee36899e6a73cf7635b11bb1723a411f324ea91Steven Ng     * {@link ACTION_PROVISION_MANAGED_DEVICE}, {@link ACTION_NDEF_DISCOVERED} and
414eee36899e6a73cf7635b11bb1723a411f324ea91Steven Ng     * {@link ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE}. These 3 actions are equivalent
415eee36899e6a73cf7635b11bb1723a411f324ea91Steven Ng     * excepts they are sent from a different source.
416eee36899e6a73cf7635b11bb1723a411f324ea91Steven Ng     *
417eee36899e6a73cf7635b11bb1723a411f324ea91Steven Ng     * @return the appropriate DevicePolicyManager declared action for the given incoming intent.
4183128ba4542f3c4c90790af0564e75950c8900961Alan Treadway     * @throws IllegalProvisioningArgumentException if intent is malformed
4193128ba4542f3c4c90790af0564e75950c8900961Alan Treadway     */
420ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franz    // TODO: Add unit tests
42172023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz    public String mapIntentToDpmAction(Intent intent)
4223128ba4542f3c4c90790af0564e75950c8900961Alan Treadway            throws IllegalProvisioningArgumentException {
4233128ba4542f3c4c90790af0564e75950c8900961Alan Treadway        if (intent == null || intent.getAction() == null) {
4243128ba4542f3c4c90790af0564e75950c8900961Alan Treadway            throw new IllegalProvisioningArgumentException("Null intent action.");
4253128ba4542f3c4c90790af0564e75950c8900961Alan Treadway        }
4263128ba4542f3c4c90790af0564e75950c8900961Alan Treadway
4273128ba4542f3c4c90790af0564e75950c8900961Alan Treadway        // Map the incoming intent to a DevicePolicyManager.ACTION_*, as there is a N:1 mapping in
4283128ba4542f3c4c90790af0564e75950c8900961Alan Treadway        // some cases.
4293128ba4542f3c4c90790af0564e75950c8900961Alan Treadway        String dpmProvisioningAction;
4303128ba4542f3c4c90790af0564e75950c8900961Alan Treadway        switch (intent.getAction()) {
4313128ba4542f3c4c90790af0564e75950c8900961Alan Treadway            // Trivial cases.
4323128ba4542f3c4c90790af0564e75950c8900961Alan Treadway            case ACTION_PROVISION_MANAGED_DEVICE:
4333128ba4542f3c4c90790af0564e75950c8900961Alan Treadway            case ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE:
4343128ba4542f3c4c90790af0564e75950c8900961Alan Treadway            case ACTION_PROVISION_MANAGED_USER:
4353128ba4542f3c4c90790af0564e75950c8900961Alan Treadway            case ACTION_PROVISION_MANAGED_PROFILE:
4363128ba4542f3c4c90790af0564e75950c8900961Alan Treadway                dpmProvisioningAction = intent.getAction();
4373128ba4542f3c4c90790af0564e75950c8900961Alan Treadway                break;
4383128ba4542f3c4c90790af0564e75950c8900961Alan Treadway
4393128ba4542f3c4c90790af0564e75950c8900961Alan Treadway            // NFC cases which need to take mime-type into account.
4403128ba4542f3c4c90790af0564e75950c8900961Alan Treadway            case ACTION_NDEF_DISCOVERED:
4413128ba4542f3c4c90790af0564e75950c8900961Alan Treadway                String mimeType = intent.getType();
442f373bd83d4b4afdc51b1cf43987521723246c19dMahaver Chopra                if (mimeType == null) {
443f373bd83d4b4afdc51b1cf43987521723246c19dMahaver Chopra                    throw new IllegalProvisioningArgumentException(
444f373bd83d4b4afdc51b1cf43987521723246c19dMahaver Chopra                            "Unknown NFC bump mime-type: " + mimeType);
445f373bd83d4b4afdc51b1cf43987521723246c19dMahaver Chopra                }
4463128ba4542f3c4c90790af0564e75950c8900961Alan Treadway                switch (mimeType) {
4473128ba4542f3c4c90790af0564e75950c8900961Alan Treadway                    case MIME_TYPE_PROVISIONING_NFC:
4483128ba4542f3c4c90790af0564e75950c8900961Alan Treadway                        dpmProvisioningAction = ACTION_PROVISION_MANAGED_DEVICE;
4493128ba4542f3c4c90790af0564e75950c8900961Alan Treadway                        break;
4503128ba4542f3c4c90790af0564e75950c8900961Alan Treadway
4513128ba4542f3c4c90790af0564e75950c8900961Alan Treadway                    default:
4523128ba4542f3c4c90790af0564e75950c8900961Alan Treadway                        throw new IllegalProvisioningArgumentException(
4533128ba4542f3c4c90790af0564e75950c8900961Alan Treadway                                "Unknown NFC bump mime-type: " + mimeType);
4543128ba4542f3c4c90790af0564e75950c8900961Alan Treadway                }
4553128ba4542f3c4c90790af0564e75950c8900961Alan Treadway                break;
4563128ba4542f3c4c90790af0564e75950c8900961Alan Treadway
457eee36899e6a73cf7635b11bb1723a411f324ea91Steven Ng            // Device owner provisioning from a trusted app.
458eee36899e6a73cf7635b11bb1723a411f324ea91Steven Ng            // TODO (b/27217042): review for new management modes in split system-user model
459eee36899e6a73cf7635b11bb1723a411f324ea91Steven Ng            case ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE:
460eee36899e6a73cf7635b11bb1723a411f324ea91Steven Ng                dpmProvisioningAction = ACTION_PROVISION_MANAGED_DEVICE;
461eee36899e6a73cf7635b11bb1723a411f324ea91Steven Ng                break;
462eee36899e6a73cf7635b11bb1723a411f324ea91Steven Ng
4633128ba4542f3c4c90790af0564e75950c8900961Alan Treadway            default:
4643128ba4542f3c4c90790af0564e75950c8900961Alan Treadway                throw new IllegalProvisioningArgumentException("Unknown intent action "
4653128ba4542f3c4c90790af0564e75950c8900961Alan Treadway                        + intent.getAction());
4663128ba4542f3c4c90790af0564e75950c8900961Alan Treadway        }
4673128ba4542f3c4c90790af0564e75950c8900961Alan Treadway        return dpmProvisioningAction;
4683128ba4542f3c4c90790af0564e75950c8900961Alan Treadway    }
4693128ba4542f3c4c90790af0564e75950c8900961Alan Treadway
4703128ba4542f3c4c90790af0564e75950c8900961Alan Treadway    /**
47172023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     * Sends an intent to trigger a factory reset.
47272023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     */
473ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franz    // TODO: Move the FR intent into a Globals class.
47472023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz    public void sendFactoryResetBroadcast(Context context, String reason) {
4756b7d9a2e5439546b8b843b1fb95e47550a251d5dLenka Trochtova        Intent intent = new Intent(Intent.ACTION_FACTORY_RESET);
476ab61c63584885391568944257108a7e50972fe6aVictor Chang        // Send explicit broadcast due to Broadcast Limitations
477ab61c63584885391568944257108a7e50972fe6aVictor Chang        intent.setPackage("android");
478aa435a10268c541f7bd61a0a254ab934e48fc875Sudheer Shanka        intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
479aa435a10268c541f7bd61a0a254ab934e48fc875Sudheer Shanka        intent.putExtra(Intent.EXTRA_REASON, reason);
480aa435a10268c541f7bd61a0a254ab934e48fc875Sudheer Shanka        context.sendBroadcast(intent);
481aa435a10268c541f7bd61a0a254ab934e48fc875Sudheer Shanka    }
482e35cc9733194b380637728d39c14dcfc0adee84bNicolas Prevot
48372023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz    /**
48472023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     * Returns whether the given provisioning action is a profile owner action.
48572023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     */
486ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franz    // TODO: Move the list of device owner actions into a Globals class.
487c79c4bc4e83edd3938e13dc4a434d5a1bb638498Benjamin Franz    public final boolean isProfileOwnerAction(String action) {
488e35cc9733194b380637728d39c14dcfc0adee84bNicolas Prevot        return action.equals(ACTION_PROVISION_MANAGED_PROFILE)
489e35cc9733194b380637728d39c14dcfc0adee84bNicolas Prevot                || action.equals(ACTION_PROVISION_MANAGED_USER);
490e35cc9733194b380637728d39c14dcfc0adee84bNicolas Prevot    }
491e35cc9733194b380637728d39c14dcfc0adee84bNicolas Prevot
49272023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz    /**
49372023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     * Returns whether the given provisioning action is a device owner action.
49472023ca7b7a818fa33e0303baf6f5baef05b5f1bBenjamin Franz     */
495ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franz    // TODO: Move the list of device owner actions into a Globals class.
496c79c4bc4e83edd3938e13dc4a434d5a1bb638498Benjamin Franz    public final boolean isDeviceOwnerAction(String action) {
497e35cc9733194b380637728d39c14dcfc0adee84bNicolas Prevot        return action.equals(ACTION_PROVISION_MANAGED_DEVICE)
498e35cc9733194b380637728d39c14dcfc0adee84bNicolas Prevot                || action.equals(ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE);
499e35cc9733194b380637728d39c14dcfc0adee84bNicolas Prevot    }
500e35cc9733194b380637728d39c14dcfc0adee84bNicolas Prevot
501ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franz    /**
502ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franz     * Returns whether the device currently has connectivity.
503ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franz     */
504ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franz    public boolean isConnectedToNetwork(Context context) {
505ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franz        NetworkInfo info = getActiveNetworkInfo(context);
506ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franz        return info != null && info.isConnected();
507ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franz    }
508ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franz
509ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franz    /**
510ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franz     * Returns whether the device is currently connected to a wifi.
511ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franz     */
512ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franz    public boolean isConnectedToWifi(Context context) {
513ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franz        NetworkInfo info = getActiveNetworkInfo(context);
514ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franz        return info != null
515ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franz                && info.isConnected()
516ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franz                && info.getType() == ConnectivityManager.TYPE_WIFI;
517ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franz    }
518ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franz
51905d5528f0accab78785b2719f4762ea91d76f681Mahaver Chopra    /**
52005d5528f0accab78785b2719f4762ea91d76f681Mahaver Chopra     * Returns the active network info of the device.
52105d5528f0accab78785b2719f4762ea91d76f681Mahaver Chopra     */
52205d5528f0accab78785b2719f4762ea91d76f681Mahaver Chopra    public NetworkInfo getActiveNetworkInfo(Context context) {
523ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franz        ConnectivityManager cm =
524ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franz                (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
52505d5528f0accab78785b2719f4762ea91d76f681Mahaver Chopra        return cm.getActiveNetworkInfo();
526ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franz    }
527ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franz
528ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franz    /**
529ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franz     * Returns whether encryption is required on this device.
530ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franz     *
531ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franz     * <p>Encryption is required if the device is not currently encrypted and the persistent
532ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franz     * system flag {@code persist.sys.no_req_encrypt} is not set.
533ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franz     */
534ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franz    public boolean isEncryptionRequired() {
535ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franz        return !isPhysicalDeviceEncrypted()
536ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franz                && !SystemProperties.getBoolean("persist.sys.no_req_encrypt", false);
537ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franz    }
538ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franz
539ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franz    /**
540ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franz     * Returns whether the device is currently encrypted.
541ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franz     */
542ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franz    public boolean isPhysicalDeviceEncrypted() {
543fce5147b7dbf266e9724dfb494cca88524b06bf8Ricky Wai        return StorageManager.isEncrypted();
544ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franz    }
545ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franz
546ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franz    /**
547ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franz     * Returns the wifi pick intent.
548ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franz     */
549ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franz    // TODO: Move this intent into a Globals class.
550ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franz    public Intent getWifiPickIntent() {
551ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franz        Intent wifiIntent = new Intent(WifiManager.ACTION_PICK_WIFI_NETWORK);
552ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franz        wifiIntent.putExtra("extra_prefs_show_button_bar", true);
553ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franz        wifiIntent.putExtra("wifi_enable_next_on_connect", true);
554ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franz        return wifiIntent;
555ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franz    }
556ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franz
557ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franz    /**
558ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franz     * Returns whether the device has a split system user.
559ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franz     *
560ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franz     * <p>Split system user means that user 0 is system only and all meat users are separate from
561ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franz     * the system user.
562ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franz     */
563ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franz    public boolean isSplitSystemUser() {
564ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franz        return UserManager.isSplitSystemUser();
565ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franz    }
566ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franz
567ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franz    /**
568ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franz     * Returns whether the currently chosen launcher supports managed profiles.
569ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franz     *
570ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franz     * <p>A launcher is deemed to support managed profiles when its target API version is at least
571ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franz     * {@link Build.VERSION_CODES#LOLLIPOP}.
572ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franz     */
573ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franz    public boolean currentLauncherSupportsManagedProfiles(Context context) {
574ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franz        Intent intent = new Intent(Intent.ACTION_MAIN);
575ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franz        intent.addCategory(Intent.CATEGORY_HOME);
576ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franz
577ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franz        PackageManager pm = context.getPackageManager();
578ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franz        ResolveInfo launcherResolveInfo = pm.resolveActivity(intent,
579ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franz                PackageManager.MATCH_DEFAULT_ONLY);
580ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franz        if (launcherResolveInfo == null) {
581ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franz            return false;
582ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franz        }
583ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franz        try {
584ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franz            // If the user has not chosen a default launcher, then launcherResolveInfo will be
585ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franz            // referring to the resolver activity. It is fine to create a managed profile in
586ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franz            // this case since there will always be at least one launcher on the device that
587ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franz            // supports managed profile feature.
588ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franz            ApplicationInfo launcherAppInfo = pm.getApplicationInfo(
589ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franz                    launcherResolveInfo.activityInfo.packageName, 0 /* default flags */);
590ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franz            return versionNumberAtLeastL(launcherAppInfo.targetSdkVersion);
591ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franz        } catch (PackageManager.NameNotFoundException e) {
592ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franz            return false;
593ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franz        }
594ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franz    }
595ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franz
596ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franz    /**
597ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franz     * Returns whether the given version number is at least lollipop.
598ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franz     *
599ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franz     * @param versionNumber the version number to be verified.
600ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franz     */
601ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franz    private boolean versionNumberAtLeastL(int versionNumber) {
602ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franz        return versionNumber >= Build.VERSION_CODES.LOLLIPOP;
603ea821b26fc845efa8058c883b0210432e9619f77Benjamin Franz    }
604974f02ac4952ba596665c71d1e71717cf8f6ef7aNicolas Prevot
605974f02ac4952ba596665c71d1e71717cf8f6ef7aNicolas Prevot    /**
606974f02ac4952ba596665c71d1e71717cf8f6ef7aNicolas Prevot     * Computes the sha 256 hash of a byte array.
607974f02ac4952ba596665c71d1e71717cf8f6ef7aNicolas Prevot     */
608945e609e967c33897df9e5f53b86e0eaa6e53e2eBenjamin Franz    @Nullable
609945e609e967c33897df9e5f53b86e0eaa6e53e2eBenjamin Franz    public byte[] computeHashOfByteArray(byte[] bytes) {
610945e609e967c33897df9e5f53b86e0eaa6e53e2eBenjamin Franz        try {
611945e609e967c33897df9e5f53b86e0eaa6e53e2eBenjamin Franz            MessageDigest md = MessageDigest.getInstance(SHA256_TYPE);
612945e609e967c33897df9e5f53b86e0eaa6e53e2eBenjamin Franz            md.update(bytes);
613945e609e967c33897df9e5f53b86e0eaa6e53e2eBenjamin Franz            return md.digest();
614945e609e967c33897df9e5f53b86e0eaa6e53e2eBenjamin Franz        } catch (NoSuchAlgorithmException e) {
615945e609e967c33897df9e5f53b86e0eaa6e53e2eBenjamin Franz            ProvisionLogger.loge("Hashing algorithm " + SHA256_TYPE + " not supported.", e);
616945e609e967c33897df9e5f53b86e0eaa6e53e2eBenjamin Franz            return null;
617945e609e967c33897df9e5f53b86e0eaa6e53e2eBenjamin Franz        }
618974f02ac4952ba596665c71d1e71717cf8f6ef7aNicolas Prevot    }
619974f02ac4952ba596665c71d1e71717cf8f6ef7aNicolas Prevot
620974f02ac4952ba596665c71d1e71717cf8f6ef7aNicolas Prevot    /**
621974f02ac4952ba596665c71d1e71717cf8f6ef7aNicolas Prevot     * Computes a hash of a file with a spcific hash algorithm.
622974f02ac4952ba596665c71d1e71717cf8f6ef7aNicolas Prevot     */
623945e609e967c33897df9e5f53b86e0eaa6e53e2eBenjamin Franz    // TODO: Add unit tests
624945e609e967c33897df9e5f53b86e0eaa6e53e2eBenjamin Franz    @Nullable
625974f02ac4952ba596665c71d1e71717cf8f6ef7aNicolas Prevot    public byte[] computeHashOfFile(String fileLocation, String hashType) {
626974f02ac4952ba596665c71d1e71717cf8f6ef7aNicolas Prevot        InputStream fis = null;
627974f02ac4952ba596665c71d1e71717cf8f6ef7aNicolas Prevot        MessageDigest md;
628974f02ac4952ba596665c71d1e71717cf8f6ef7aNicolas Prevot        byte hash[] = null;
629974f02ac4952ba596665c71d1e71717cf8f6ef7aNicolas Prevot        try {
630974f02ac4952ba596665c71d1e71717cf8f6ef7aNicolas Prevot            md = MessageDigest.getInstance(hashType);
631974f02ac4952ba596665c71d1e71717cf8f6ef7aNicolas Prevot        } catch (NoSuchAlgorithmException e) {
632974f02ac4952ba596665c71d1e71717cf8f6ef7aNicolas Prevot            ProvisionLogger.loge("Hashing algorithm " + hashType + " not supported.", e);
633974f02ac4952ba596665c71d1e71717cf8f6ef7aNicolas Prevot            return null;
634974f02ac4952ba596665c71d1e71717cf8f6ef7aNicolas Prevot        }
635974f02ac4952ba596665c71d1e71717cf8f6ef7aNicolas Prevot        try {
636974f02ac4952ba596665c71d1e71717cf8f6ef7aNicolas Prevot            fis = new FileInputStream(fileLocation);
637974f02ac4952ba596665c71d1e71717cf8f6ef7aNicolas Prevot
638974f02ac4952ba596665c71d1e71717cf8f6ef7aNicolas Prevot            byte[] buffer = new byte[256];
639974f02ac4952ba596665c71d1e71717cf8f6ef7aNicolas Prevot            int n = 0;
640974f02ac4952ba596665c71d1e71717cf8f6ef7aNicolas Prevot            while (n != -1) {
641974f02ac4952ba596665c71d1e71717cf8f6ef7aNicolas Prevot                n = fis.read(buffer);
642974f02ac4952ba596665c71d1e71717cf8f6ef7aNicolas Prevot                if (n > 0) {
643974f02ac4952ba596665c71d1e71717cf8f6ef7aNicolas Prevot                    md.update(buffer, 0, n);
644974f02ac4952ba596665c71d1e71717cf8f6ef7aNicolas Prevot                }
645974f02ac4952ba596665c71d1e71717cf8f6ef7aNicolas Prevot            }
646974f02ac4952ba596665c71d1e71717cf8f6ef7aNicolas Prevot            hash = md.digest();
647974f02ac4952ba596665c71d1e71717cf8f6ef7aNicolas Prevot        } catch (IOException e) {
648974f02ac4952ba596665c71d1e71717cf8f6ef7aNicolas Prevot            ProvisionLogger.loge("IO error.", e);
649974f02ac4952ba596665c71d1e71717cf8f6ef7aNicolas Prevot        } finally {
650974f02ac4952ba596665c71d1e71717cf8f6ef7aNicolas Prevot            // Close input stream quietly.
651974f02ac4952ba596665c71d1e71717cf8f6ef7aNicolas Prevot            try {
652974f02ac4952ba596665c71d1e71717cf8f6ef7aNicolas Prevot                if (fis != null) {
653974f02ac4952ba596665c71d1e71717cf8f6ef7aNicolas Prevot                    fis.close();
654974f02ac4952ba596665c71d1e71717cf8f6ef7aNicolas Prevot                }
655974f02ac4952ba596665c71d1e71717cf8f6ef7aNicolas Prevot            } catch (IOException e) {
656974f02ac4952ba596665c71d1e71717cf8f6ef7aNicolas Prevot                // Ignore.
657974f02ac4952ba596665c71d1e71717cf8f6ef7aNicolas Prevot            }
658974f02ac4952ba596665c71d1e71717cf8f6ef7aNicolas Prevot        }
659974f02ac4952ba596665c71d1e71717cf8f6ef7aNicolas Prevot        return hash;
660974f02ac4952ba596665c71d1e71717cf8f6ef7aNicolas Prevot    }
661b38680c8eebfaf0af71efaf042383d06a2a8350aNicolas Prevot
662b38680c8eebfaf0af71efaf042383d06a2a8350aNicolas Prevot    public boolean isBrightColor(int color) {
663b38680c8eebfaf0af71efaf042383d06a2a8350aNicolas Prevot        // This comes from the YIQ transformation. We're using the formula:
664b38680c8eebfaf0af71efaf042383d06a2a8350aNicolas Prevot        // Y = .299 * R + .587 * G + .114 * B
665b38680c8eebfaf0af71efaf042383d06a2a8350aNicolas Prevot        return Color.red(color) * 299 + Color.green(color) * 587 + Color.blue(color) * 114
666b38680c8eebfaf0af71efaf042383d06a2a8350aNicolas Prevot                >= 1000 * THRESHOLD_BRIGHT_COLOR;
667b38680c8eebfaf0af71efaf042383d06a2a8350aNicolas Prevot    }
668cb4628e81cf01fa83b92a68b6313282efc176d48Mahaver Chopra
669cb4628e81cf01fa83b92a68b6313282efc176d48Mahaver Chopra    /**
670cb4628e81cf01fa83b92a68b6313282efc176d48Mahaver Chopra     * Returns whether given intent can be resolved for the user.
671cb4628e81cf01fa83b92a68b6313282efc176d48Mahaver Chopra     */
672cb4628e81cf01fa83b92a68b6313282efc176d48Mahaver Chopra    public boolean canResolveIntentAsUser(Context context, Intent intent, int userId) {
673cb4628e81cf01fa83b92a68b6313282efc176d48Mahaver Chopra        return intent != null
674cb4628e81cf01fa83b92a68b6313282efc176d48Mahaver Chopra                && context.getPackageManager().resolveActivityAsUser(intent, 0, userId) != null;
675cb4628e81cf01fa83b92a68b6313282efc176d48Mahaver Chopra    }
67680ae370242ebd15119d1a6e9e5026e036bfe1cf7Victor Chang
67780ae370242ebd15119d1a6e9e5026e036bfe1cf7Victor Chang    public boolean isPackageDeviceOwner(DevicePolicyManager dpm, String packageName) {
67880ae370242ebd15119d1a6e9e5026e036bfe1cf7Victor Chang        final ComponentName deviceOwner = dpm.getDeviceOwnerComponentOnCallingUser();
67980ae370242ebd15119d1a6e9e5026e036bfe1cf7Victor Chang        return deviceOwner != null && deviceOwner.getPackageName().equals(packageName);
68080ae370242ebd15119d1a6e9e5026e036bfe1cf7Victor Chang    }
6816b7d9a2e5439546b8b843b1fb95e47550a251d5dLenka Trochtova}
682