Loading core/api/system-current.txt 100644 → 100755 +2 −0 Original line number Original line Diff line number Diff line Loading @@ -924,6 +924,7 @@ package android.app.admin { } } public class DevicePolicyManager { public class DevicePolicyManager { method @Nullable public android.content.Intent createProvisioningIntentFromNfcIntent(@NonNull android.content.Intent); method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public boolean getBluetoothContactSharingDisabled(@NonNull android.os.UserHandle); method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public boolean getBluetoothContactSharingDisabled(@NonNull android.os.UserHandle); method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public String getDeviceOwner(); method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public String getDeviceOwner(); method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, "android.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS"}) public android.content.ComponentName getDeviceOwnerComponentOnAnyUser(); method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, "android.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS"}) public android.content.ComponentName getDeviceOwnerComponentOnAnyUser(); Loading Loading @@ -972,6 +973,7 @@ package android.app.admin { field public static final int FLAG_SUPPORTED_MODES_PERSONALLY_OWNED = 2; // 0x2 field public static final int FLAG_SUPPORTED_MODES_PERSONALLY_OWNED = 2; // 0x2 field public static final int PROVISIONING_TRIGGER_CLOUD_ENROLLMENT = 1; // 0x1 field public static final int PROVISIONING_TRIGGER_CLOUD_ENROLLMENT = 1; // 0x1 field public static final int PROVISIONING_TRIGGER_MANAGED_ACCOUNT = 4; // 0x4 field public static final int PROVISIONING_TRIGGER_MANAGED_ACCOUNT = 4; // 0x4 field public static final int PROVISIONING_TRIGGER_NFC = 5; // 0x5 field @Deprecated public static final int PROVISIONING_TRIGGER_PERSISTENT_DEVICE_OWNER = 3; // 0x3 field @Deprecated public static final int PROVISIONING_TRIGGER_PERSISTENT_DEVICE_OWNER = 3; // 0x3 field public static final int PROVISIONING_TRIGGER_QR_CODE = 2; // 0x2 field public static final int PROVISIONING_TRIGGER_QR_CODE = 2; // 0x2 field public static final int PROVISIONING_TRIGGER_UNSPECIFIED = 0; // 0x0 field public static final int PROVISIONING_TRIGGER_UNSPECIFIED = 0; // 0x0 core/java/android/app/admin/DevicePolicyManager.java +49 −1 Original line number Original line Diff line number Diff line Loading @@ -56,6 +56,7 @@ import android.graphics.Bitmap; import android.net.PrivateDnsConnectivityChecker; import android.net.PrivateDnsConnectivityChecker; import android.net.ProxyInfo; import android.net.ProxyInfo; import android.net.Uri; import android.net.Uri; import android.nfc.NfcAdapter; import android.os.Build; import android.os.Build; import android.os.Bundle; import android.os.Bundle; import android.os.ParcelFileDescriptor; import android.os.ParcelFileDescriptor; Loading Loading @@ -1216,7 +1217,8 @@ public class DevicePolicyManager { PROVISIONING_TRIGGER_CLOUD_ENROLLMENT, PROVISIONING_TRIGGER_CLOUD_ENROLLMENT, PROVISIONING_TRIGGER_QR_CODE, PROVISIONING_TRIGGER_QR_CODE, PROVISIONING_TRIGGER_PERSISTENT_DEVICE_OWNER, PROVISIONING_TRIGGER_PERSISTENT_DEVICE_OWNER, PROVISIONING_TRIGGER_MANAGED_ACCOUNT PROVISIONING_TRIGGER_MANAGED_ACCOUNT, PROVISIONING_TRIGGER_NFC }) }) @Retention(RetentionPolicy.SOURCE) @Retention(RetentionPolicy.SOURCE) public @interface ProvisioningTrigger {} public @interface ProvisioningTrigger {} Loading Loading @@ -1254,6 +1256,7 @@ public class DevicePolicyManager { * @see #PROVISIONING_TRIGGER_CLOUD_ENROLLMENT * @see #PROVISIONING_TRIGGER_CLOUD_ENROLLMENT * @see #PROVISIONING_TRIGGER_QR_CODE * @see #PROVISIONING_TRIGGER_QR_CODE * @see #PROVISIONING_TRIGGER_MANAGED_ACCOUNT * @see #PROVISIONING_TRIGGER_MANAGED_ACCOUNT * @see #PROVISIONING_TRIGGER_NFC * @hide * @hide */ */ @SystemApi @SystemApi Loading @@ -1265,6 +1268,7 @@ public class DevicePolicyManager { * @see #PROVISIONING_TRIGGER_QR_CODE * @see #PROVISIONING_TRIGGER_QR_CODE * @see #PROVISIONING_TRIGGER_MANAGED_ACCOUNT * @see #PROVISIONING_TRIGGER_MANAGED_ACCOUNT * @see #PROVISIONING_TRIGGER_UNSPECIFIED * @see #PROVISIONING_TRIGGER_UNSPECIFIED * @see #PROVISIONING_TRIGGER_NFC * @hide * @hide */ */ @SystemApi @SystemApi Loading @@ -1276,6 +1280,7 @@ public class DevicePolicyManager { * @see #PROVISIONING_TRIGGER_CLOUD_ENROLLMENT * @see #PROVISIONING_TRIGGER_CLOUD_ENROLLMENT * @see #PROVISIONING_TRIGGER_MANAGED_ACCOUNT * @see #PROVISIONING_TRIGGER_MANAGED_ACCOUNT * @see #PROVISIONING_TRIGGER_UNSPECIFIED * @see #PROVISIONING_TRIGGER_UNSPECIFIED * @see #PROVISIONING_TRIGGER_NFC * @hide * @hide */ */ @SystemApi @SystemApi Loading @@ -1295,6 +1300,7 @@ public class DevicePolicyManager { * @see #PROVISIONING_TRIGGER_CLOUD_ENROLLMENT * @see #PROVISIONING_TRIGGER_CLOUD_ENROLLMENT * @see #PROVISIONING_TRIGGER_QR_CODE * @see #PROVISIONING_TRIGGER_QR_CODE * @see #PROVISIONING_TRIGGER_UNSPECIFIED * @see #PROVISIONING_TRIGGER_UNSPECIFIED * @see #PROVISIONING_TRIGGER_NFC * @hide * @hide */ */ @SystemApi @SystemApi Loading @@ -1308,11 +1314,24 @@ public class DevicePolicyManager { * @see #PROVISIONING_TRIGGER_CLOUD_ENROLLMENT * @see #PROVISIONING_TRIGGER_CLOUD_ENROLLMENT * @see #PROVISIONING_TRIGGER_QR_CODE * @see #PROVISIONING_TRIGGER_QR_CODE * @see #PROVISIONING_TRIGGER_UNSPECIFIED * @see #PROVISIONING_TRIGGER_UNSPECIFIED * @see #PROVISIONING_TRIGGER_NFC * @hide * @hide */ */ @SystemApi @SystemApi public static final int PROVISIONING_TRIGGER_MANAGED_ACCOUNT = 4; public static final int PROVISIONING_TRIGGER_MANAGED_ACCOUNT = 4; /** * A value for {@link #EXTRA_PROVISIONING_TRIGGER} indicating that the provisioning is * triggered by tapping an NFC tag. * @see #PROVISIONING_TRIGGER_CLOUD_ENROLLMENT * @see #PROVISIONING_TRIGGER_QR_CODE * @see #PROVISIONING_TRIGGER_UNSPECIFIED * @see #PROVISIONING_TRIGGER_MANAGED_ACCOUNT * @hide */ @SystemApi public static final int PROVISIONING_TRIGGER_NFC = 5; /** /** * Flag for {@link #EXTRA_PROVISIONING_SUPPORTED_MODES} indicating that provisioning is * Flag for {@link #EXTRA_PROVISIONING_SUPPORTED_MODES} indicating that provisioning is * organization-owned. * organization-owned. Loading Loading @@ -14009,4 +14028,33 @@ public class DevicePolicyManager { throw e.rethrowFromSystemServer(); throw e.rethrowFromSystemServer(); } } } } /** * Creates a {@link #ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE} intent * from the provided {@code nfcIntent}. * * <p>Prerequisites to create the provisioning intent: * * <ul> * <li>{@code nfcIntent}'s action is {@link NfcAdapter#ACTION_NDEF_DISCOVERED}</li> * <li>{@code nfcIntent}'s NFC properties contain either * {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME} or * {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME} </li> * </ul> * * This method returns {@code null} if the prerequisites are not met or if an error occurs * when reading the NFC properties. * * @param nfcIntent the nfc intent generated from scanning a NFC tag * @return a {@link #ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE} intent with * intent extras as read by {@code nfcIntent}'s NFC properties or {@code null} if the * prerequisites are not met or if an error occurs when reading the NFC properties. * * @hide */ @Nullable @SystemApi public Intent createProvisioningIntentFromNfcIntent(@NonNull Intent nfcIntent) { return ProvisioningIntentHelper.createProvisioningIntentFromNfcIntent(nfcIntent); } } } core/java/android/app/admin/ProvisioningIntentHelper.java 0 → 100644 +178 −0 Original line number Original line Diff line number Diff line /* * Copyright (C) 2021 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.app.admin; import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE; import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME; import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME; import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_TRIGGER; import static android.app.admin.DevicePolicyManager.MIME_TYPE_PROVISIONING_NFC; import static android.app.admin.DevicePolicyManager.PROVISIONING_TRIGGER_NFC; import static android.nfc.NfcAdapter.EXTRA_NDEF_MESSAGES; import static java.nio.charset.StandardCharsets.UTF_8; import static java.util.Objects.requireNonNull; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.ComponentName; import android.content.Intent; import android.nfc.NdefMessage; import android.nfc.NdefRecord; import android.nfc.NfcAdapter; import android.os.Bundle; import android.os.Parcelable; import android.util.Log; import java.io.IOException; import java.io.StringReader; import java.util.Enumeration; import java.util.Properties; /** * Utility class that provides functionality to create provisioning intents from nfc intents. */ final class ProvisioningIntentHelper { private static final String TAG = "ProvisioningIntentHelper"; /** * This class is never instantiated */ private ProvisioningIntentHelper() { } @Nullable public static Intent createProvisioningIntentFromNfcIntent(@NonNull Intent nfcIntent) { requireNonNull(nfcIntent); if (!NfcAdapter.ACTION_NDEF_DISCOVERED.equals(nfcIntent.getAction())) { Log.e(TAG, "Wrong Nfc action: " + nfcIntent.getAction()); return null; } NdefRecord firstRecord = getFirstNdefRecord(nfcIntent); if (firstRecord != null) { return createProvisioningIntentFromNdefRecord(firstRecord); } return null; } private static Intent createProvisioningIntentFromNdefRecord(NdefRecord firstRecord) { requireNonNull(firstRecord); Properties properties = loadPropertiesFromPayload(firstRecord.getPayload()); if (properties == null) { Log.e(TAG, "Failed to load NdefRecord properties."); return null; } Bundle bundle = createBundleFromProperties(properties); if (!containsRequiredProvisioningExtras(bundle)) { Log.e(TAG, "Bundle does not contain the required provisioning extras."); return null; } return createProvisioningIntentFromBundle(bundle); } private static Properties loadPropertiesFromPayload(byte[] payload) { Properties properties = new Properties(); try { properties.load(new StringReader(new String(payload, UTF_8))); } catch (IOException e) { Log.e(TAG, "NFC Intent properties loading failed."); return null; } return properties; } private static Bundle createBundleFromProperties(Properties properties) { Enumeration propertyNames = properties.propertyNames(); Bundle bundle = new Bundle(); while (propertyNames.hasMoreElements()) { String propertyName = (String) propertyNames.nextElement(); addPropertyToBundle(propertyName, properties, bundle); } return bundle; } private static void addPropertyToBundle( String propertyName, Properties properties, Bundle bundle) { if(EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME.equals(propertyName)) { ComponentName componentName = ComponentName.unflattenFromString( properties.getProperty(propertyName)); bundle.putParcelable(propertyName, componentName); } else { bundle.putString(propertyName, properties.getProperty(propertyName)); } } private static Intent createProvisioningIntentFromBundle(Bundle bundle) { requireNonNull(bundle); Intent provisioningIntent = new Intent(ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE); provisioningIntent.putExtras(bundle); provisioningIntent.putExtra(EXTRA_PROVISIONING_TRIGGER, PROVISIONING_TRIGGER_NFC); return provisioningIntent; } private static boolean containsRequiredProvisioningExtras(Bundle bundle) { return bundle.containsKey(EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME) || bundle.containsKey(EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME); } /** * Returns the first {@link NdefRecord} found with a recognized MIME-type */ private static NdefRecord getFirstNdefRecord(Intent nfcIntent) { Parcelable[] ndefMessages = nfcIntent.getParcelableArrayExtra(EXTRA_NDEF_MESSAGES); if (ndefMessages == null) { Log.i(TAG, "No EXTRA_NDEF_MESSAGES from nfcIntent"); return null; } for (Parcelable rawMsg : ndefMessages) { NdefMessage msg = (NdefMessage) rawMsg; for (NdefRecord record : msg.getRecords()) { String mimeType = new String(record.getType(), UTF_8); // Only one first message with NFC_MIME_TYPE is used. if (MIME_TYPE_PROVISIONING_NFC.equals(mimeType)) { return record; } // Assume only first record of message is used. break; } } Log.i(TAG, "No compatible records found on nfcIntent"); return null; } } Loading
core/api/system-current.txt 100644 → 100755 +2 −0 Original line number Original line Diff line number Diff line Loading @@ -924,6 +924,7 @@ package android.app.admin { } } public class DevicePolicyManager { public class DevicePolicyManager { method @Nullable public android.content.Intent createProvisioningIntentFromNfcIntent(@NonNull android.content.Intent); method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public boolean getBluetoothContactSharingDisabled(@NonNull android.os.UserHandle); method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public boolean getBluetoothContactSharingDisabled(@NonNull android.os.UserHandle); method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public String getDeviceOwner(); method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public String getDeviceOwner(); method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, "android.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS"}) public android.content.ComponentName getDeviceOwnerComponentOnAnyUser(); method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, "android.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS"}) public android.content.ComponentName getDeviceOwnerComponentOnAnyUser(); Loading Loading @@ -972,6 +973,7 @@ package android.app.admin { field public static final int FLAG_SUPPORTED_MODES_PERSONALLY_OWNED = 2; // 0x2 field public static final int FLAG_SUPPORTED_MODES_PERSONALLY_OWNED = 2; // 0x2 field public static final int PROVISIONING_TRIGGER_CLOUD_ENROLLMENT = 1; // 0x1 field public static final int PROVISIONING_TRIGGER_CLOUD_ENROLLMENT = 1; // 0x1 field public static final int PROVISIONING_TRIGGER_MANAGED_ACCOUNT = 4; // 0x4 field public static final int PROVISIONING_TRIGGER_MANAGED_ACCOUNT = 4; // 0x4 field public static final int PROVISIONING_TRIGGER_NFC = 5; // 0x5 field @Deprecated public static final int PROVISIONING_TRIGGER_PERSISTENT_DEVICE_OWNER = 3; // 0x3 field @Deprecated public static final int PROVISIONING_TRIGGER_PERSISTENT_DEVICE_OWNER = 3; // 0x3 field public static final int PROVISIONING_TRIGGER_QR_CODE = 2; // 0x2 field public static final int PROVISIONING_TRIGGER_QR_CODE = 2; // 0x2 field public static final int PROVISIONING_TRIGGER_UNSPECIFIED = 0; // 0x0 field public static final int PROVISIONING_TRIGGER_UNSPECIFIED = 0; // 0x0
core/java/android/app/admin/DevicePolicyManager.java +49 −1 Original line number Original line Diff line number Diff line Loading @@ -56,6 +56,7 @@ import android.graphics.Bitmap; import android.net.PrivateDnsConnectivityChecker; import android.net.PrivateDnsConnectivityChecker; import android.net.ProxyInfo; import android.net.ProxyInfo; import android.net.Uri; import android.net.Uri; import android.nfc.NfcAdapter; import android.os.Build; import android.os.Build; import android.os.Bundle; import android.os.Bundle; import android.os.ParcelFileDescriptor; import android.os.ParcelFileDescriptor; Loading Loading @@ -1216,7 +1217,8 @@ public class DevicePolicyManager { PROVISIONING_TRIGGER_CLOUD_ENROLLMENT, PROVISIONING_TRIGGER_CLOUD_ENROLLMENT, PROVISIONING_TRIGGER_QR_CODE, PROVISIONING_TRIGGER_QR_CODE, PROVISIONING_TRIGGER_PERSISTENT_DEVICE_OWNER, PROVISIONING_TRIGGER_PERSISTENT_DEVICE_OWNER, PROVISIONING_TRIGGER_MANAGED_ACCOUNT PROVISIONING_TRIGGER_MANAGED_ACCOUNT, PROVISIONING_TRIGGER_NFC }) }) @Retention(RetentionPolicy.SOURCE) @Retention(RetentionPolicy.SOURCE) public @interface ProvisioningTrigger {} public @interface ProvisioningTrigger {} Loading Loading @@ -1254,6 +1256,7 @@ public class DevicePolicyManager { * @see #PROVISIONING_TRIGGER_CLOUD_ENROLLMENT * @see #PROVISIONING_TRIGGER_CLOUD_ENROLLMENT * @see #PROVISIONING_TRIGGER_QR_CODE * @see #PROVISIONING_TRIGGER_QR_CODE * @see #PROVISIONING_TRIGGER_MANAGED_ACCOUNT * @see #PROVISIONING_TRIGGER_MANAGED_ACCOUNT * @see #PROVISIONING_TRIGGER_NFC * @hide * @hide */ */ @SystemApi @SystemApi Loading @@ -1265,6 +1268,7 @@ public class DevicePolicyManager { * @see #PROVISIONING_TRIGGER_QR_CODE * @see #PROVISIONING_TRIGGER_QR_CODE * @see #PROVISIONING_TRIGGER_MANAGED_ACCOUNT * @see #PROVISIONING_TRIGGER_MANAGED_ACCOUNT * @see #PROVISIONING_TRIGGER_UNSPECIFIED * @see #PROVISIONING_TRIGGER_UNSPECIFIED * @see #PROVISIONING_TRIGGER_NFC * @hide * @hide */ */ @SystemApi @SystemApi Loading @@ -1276,6 +1280,7 @@ public class DevicePolicyManager { * @see #PROVISIONING_TRIGGER_CLOUD_ENROLLMENT * @see #PROVISIONING_TRIGGER_CLOUD_ENROLLMENT * @see #PROVISIONING_TRIGGER_MANAGED_ACCOUNT * @see #PROVISIONING_TRIGGER_MANAGED_ACCOUNT * @see #PROVISIONING_TRIGGER_UNSPECIFIED * @see #PROVISIONING_TRIGGER_UNSPECIFIED * @see #PROVISIONING_TRIGGER_NFC * @hide * @hide */ */ @SystemApi @SystemApi Loading @@ -1295,6 +1300,7 @@ public class DevicePolicyManager { * @see #PROVISIONING_TRIGGER_CLOUD_ENROLLMENT * @see #PROVISIONING_TRIGGER_CLOUD_ENROLLMENT * @see #PROVISIONING_TRIGGER_QR_CODE * @see #PROVISIONING_TRIGGER_QR_CODE * @see #PROVISIONING_TRIGGER_UNSPECIFIED * @see #PROVISIONING_TRIGGER_UNSPECIFIED * @see #PROVISIONING_TRIGGER_NFC * @hide * @hide */ */ @SystemApi @SystemApi Loading @@ -1308,11 +1314,24 @@ public class DevicePolicyManager { * @see #PROVISIONING_TRIGGER_CLOUD_ENROLLMENT * @see #PROVISIONING_TRIGGER_CLOUD_ENROLLMENT * @see #PROVISIONING_TRIGGER_QR_CODE * @see #PROVISIONING_TRIGGER_QR_CODE * @see #PROVISIONING_TRIGGER_UNSPECIFIED * @see #PROVISIONING_TRIGGER_UNSPECIFIED * @see #PROVISIONING_TRIGGER_NFC * @hide * @hide */ */ @SystemApi @SystemApi public static final int PROVISIONING_TRIGGER_MANAGED_ACCOUNT = 4; public static final int PROVISIONING_TRIGGER_MANAGED_ACCOUNT = 4; /** * A value for {@link #EXTRA_PROVISIONING_TRIGGER} indicating that the provisioning is * triggered by tapping an NFC tag. * @see #PROVISIONING_TRIGGER_CLOUD_ENROLLMENT * @see #PROVISIONING_TRIGGER_QR_CODE * @see #PROVISIONING_TRIGGER_UNSPECIFIED * @see #PROVISIONING_TRIGGER_MANAGED_ACCOUNT * @hide */ @SystemApi public static final int PROVISIONING_TRIGGER_NFC = 5; /** /** * Flag for {@link #EXTRA_PROVISIONING_SUPPORTED_MODES} indicating that provisioning is * Flag for {@link #EXTRA_PROVISIONING_SUPPORTED_MODES} indicating that provisioning is * organization-owned. * organization-owned. Loading Loading @@ -14009,4 +14028,33 @@ public class DevicePolicyManager { throw e.rethrowFromSystemServer(); throw e.rethrowFromSystemServer(); } } } } /** * Creates a {@link #ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE} intent * from the provided {@code nfcIntent}. * * <p>Prerequisites to create the provisioning intent: * * <ul> * <li>{@code nfcIntent}'s action is {@link NfcAdapter#ACTION_NDEF_DISCOVERED}</li> * <li>{@code nfcIntent}'s NFC properties contain either * {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME} or * {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME} </li> * </ul> * * This method returns {@code null} if the prerequisites are not met or if an error occurs * when reading the NFC properties. * * @param nfcIntent the nfc intent generated from scanning a NFC tag * @return a {@link #ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE} intent with * intent extras as read by {@code nfcIntent}'s NFC properties or {@code null} if the * prerequisites are not met or if an error occurs when reading the NFC properties. * * @hide */ @Nullable @SystemApi public Intent createProvisioningIntentFromNfcIntent(@NonNull Intent nfcIntent) { return ProvisioningIntentHelper.createProvisioningIntentFromNfcIntent(nfcIntent); } } }
core/java/android/app/admin/ProvisioningIntentHelper.java 0 → 100644 +178 −0 Original line number Original line Diff line number Diff line /* * Copyright (C) 2021 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.app.admin; import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE; import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME; import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME; import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_TRIGGER; import static android.app.admin.DevicePolicyManager.MIME_TYPE_PROVISIONING_NFC; import static android.app.admin.DevicePolicyManager.PROVISIONING_TRIGGER_NFC; import static android.nfc.NfcAdapter.EXTRA_NDEF_MESSAGES; import static java.nio.charset.StandardCharsets.UTF_8; import static java.util.Objects.requireNonNull; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.ComponentName; import android.content.Intent; import android.nfc.NdefMessage; import android.nfc.NdefRecord; import android.nfc.NfcAdapter; import android.os.Bundle; import android.os.Parcelable; import android.util.Log; import java.io.IOException; import java.io.StringReader; import java.util.Enumeration; import java.util.Properties; /** * Utility class that provides functionality to create provisioning intents from nfc intents. */ final class ProvisioningIntentHelper { private static final String TAG = "ProvisioningIntentHelper"; /** * This class is never instantiated */ private ProvisioningIntentHelper() { } @Nullable public static Intent createProvisioningIntentFromNfcIntent(@NonNull Intent nfcIntent) { requireNonNull(nfcIntent); if (!NfcAdapter.ACTION_NDEF_DISCOVERED.equals(nfcIntent.getAction())) { Log.e(TAG, "Wrong Nfc action: " + nfcIntent.getAction()); return null; } NdefRecord firstRecord = getFirstNdefRecord(nfcIntent); if (firstRecord != null) { return createProvisioningIntentFromNdefRecord(firstRecord); } return null; } private static Intent createProvisioningIntentFromNdefRecord(NdefRecord firstRecord) { requireNonNull(firstRecord); Properties properties = loadPropertiesFromPayload(firstRecord.getPayload()); if (properties == null) { Log.e(TAG, "Failed to load NdefRecord properties."); return null; } Bundle bundle = createBundleFromProperties(properties); if (!containsRequiredProvisioningExtras(bundle)) { Log.e(TAG, "Bundle does not contain the required provisioning extras."); return null; } return createProvisioningIntentFromBundle(bundle); } private static Properties loadPropertiesFromPayload(byte[] payload) { Properties properties = new Properties(); try { properties.load(new StringReader(new String(payload, UTF_8))); } catch (IOException e) { Log.e(TAG, "NFC Intent properties loading failed."); return null; } return properties; } private static Bundle createBundleFromProperties(Properties properties) { Enumeration propertyNames = properties.propertyNames(); Bundle bundle = new Bundle(); while (propertyNames.hasMoreElements()) { String propertyName = (String) propertyNames.nextElement(); addPropertyToBundle(propertyName, properties, bundle); } return bundle; } private static void addPropertyToBundle( String propertyName, Properties properties, Bundle bundle) { if(EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME.equals(propertyName)) { ComponentName componentName = ComponentName.unflattenFromString( properties.getProperty(propertyName)); bundle.putParcelable(propertyName, componentName); } else { bundle.putString(propertyName, properties.getProperty(propertyName)); } } private static Intent createProvisioningIntentFromBundle(Bundle bundle) { requireNonNull(bundle); Intent provisioningIntent = new Intent(ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE); provisioningIntent.putExtras(bundle); provisioningIntent.putExtra(EXTRA_PROVISIONING_TRIGGER, PROVISIONING_TRIGGER_NFC); return provisioningIntent; } private static boolean containsRequiredProvisioningExtras(Bundle bundle) { return bundle.containsKey(EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME) || bundle.containsKey(EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME); } /** * Returns the first {@link NdefRecord} found with a recognized MIME-type */ private static NdefRecord getFirstNdefRecord(Intent nfcIntent) { Parcelable[] ndefMessages = nfcIntent.getParcelableArrayExtra(EXTRA_NDEF_MESSAGES); if (ndefMessages == null) { Log.i(TAG, "No EXTRA_NDEF_MESSAGES from nfcIntent"); return null; } for (Parcelable rawMsg : ndefMessages) { NdefMessage msg = (NdefMessage) rawMsg; for (NdefRecord record : msg.getRecords()) { String mimeType = new String(record.getType(), UTF_8); // Only one first message with NFC_MIME_TYPE is used. if (MIME_TYPE_PROVISIONING_NFC.equals(mimeType)) { return record; } // Assume only first record of message is used. break; } } Log.i(TAG, "No compatible records found on nfcIntent"); return null; } }