Implement user accounts

There are two primary user identity types for Android enterprise enrollments: Managed Google Play accounts and Managed Google Accounts. Managed Google Play accounts are device-centric, meaning they aren't tied to a specific user's Google identity. In contrast, Managed Google Accounts are linked to a user's corporate Google identity, which improves the user experience by keeping them logged in on their devices.

Managed Google Play accounts used to be the standard. However, Google now encourages all new development to use the improved enrollment flow, which defaults to creating Managed Google Accounts.

While guidance for the older implementation is provided at the end of this document for context, all new development should follow the new enrollment flow detailed here.

Overview

The improved device enrollment flow streamlines device setup by leveraging several new components and changing how custom Device Policy Controllers (DPCs) are implemented. This new approach requires custom DPC solutions to integrate with the Android Management API (AMAPI) SDK and Android Device Policy to perform device preparation and user enrollment functions.

The AMAPI SDK provides the necessary APIs for interacting with the Android Device Policy on the device itself. On the server side, Enterprise Mobility Management (EMM) solutions will use the Play EMM API to generate the enrollment tokens required to initiate the device enrollment process.

The Android Device Policy application now assumes a central role in handling device-side operations. The AMAPI SDK is used to manage its installation and necessary updates on the device. Android Device Policy also takes over the user authentication flow, handling user authentication directly and providing the user's identity to the EMM. If Google cannot authenticate the user for any reason, a new managed Google Play account is created and added to the device as a fallback.

API Integration

Before getting started, verify that you are using the latest version of the Play EMM API client and the AMAPI SDK.

Enrollment implementation guide

This guide provides the necessary steps for implementing enrollment. It covers preparing the environment, handling different enrollment methods, and managing the device lifecycle.

Prepare environment

Before initiating the account setup, it is necessary to prepare the device environment. This preparation entails updating the Play Store to its latest iteration and silently installing the Android Device Policy (com.google.android.apps.work.clouddpc) onto the device. Android Device Policy installation is essential as it houses critical components of the Account Setup process. EMMs need not perform manual environment preparation. Instead, they should use the EnvironmentClient, as documented at and adhere to the provided code examples.

Sample code

Before being able to use the AccountSetup API to add the work account on the device, the DPC must first verify that the device environment is ready.

  • Use EnvironmentClientFactory to instantiate an EnvironmentClient and call prepareEnvironment or prepareEnvironmentAsync

    val notificationReceiverServiceName = ComponentName(context,
    NotificationReceiver::class.java)
    
    // An EMM should implement android.app.admin.DeviceAdminReceiver and use that
    // class to instantiate a ComponentName
    
    val admin = ComponentName(this, com.example.dpc.DeviceAdminReceiver::class.java)
    
    EnvironmentClientFactory.create(context)
        .prepareEnvironment(
            PrepareEnvironmentRequest.builder()
                .setRoles(
                    listOf(
                        Role.builder().setRoleType(
                            Role.RoleType.DEVICE_POLICY_CONTROLLER
                        ).build()
                    )
                )
        .setAdmin(admin)
                .build(),
              notificationReceiverServiceName,
            )
    
    [Proceed with AccountSetup]
    
    

This operation could take several seconds or minutes, since applications may be installed or updated to verify a proper working environment. Google recommends starting this process as early as possible in the background and showing appropriate UI while the user waits. When the operation completes, the device is ready for the DPC to use the AccountSetup API.

Enrollment flow

EMMs must discontinue using users.generateAuthenticationToken() and users.insert() for all devices. Instead, EMMs must call the on-device API to perform end-user authentication. The new API will return the userId and email to the DPC. If Google is not able to authenticate the user, a Managed Google Play Account will be created and added to the device. In this case, Google will return the userId of that account.

Google now introduces the use of enrollment tokens, which must be passed to the authentication API. EMMs determine when and how to create the token, and it can be part of an existing enrollment payload (e.g., a QR code or Zero-touch configuration).

However, Google recommends creating the token on demand and replacing the existing API for Managed Google Play Accounts with the new API to minimize the change.

Typical DPC integration with previous APIs
Figure 1. Typical DPC integration with previous APIs
Example DPC integration with new APIs for userless devices
Figure 2. Example DPC integration with new APIs for userless devices
Example DPC integration with new APIs for user devices
Figure 3. Example DPC integration with new APIs for user devices

The improved custom DPC enrollment flow involves the following steps:

  1. Create Enrollment Token: The EMM creates an enrollment token using the Play EMM API.
  2. Prepare Environment: The custom DPC uses the Prepare Environment flow to verify the device is ready for enrollment.
  3. Initiate Enrollment: The custom DPC invokes the startAccountSetup API in the AMAPI SDK, passing the enrollment token. Note: The DPC must be either device owner or profile owner before calling this API.
  4. Launch Google authentication activity: If required, the custom DPC invokes the launchAuthenticationActivity API in the AMAPI SDK, passing the AccountSetupAttempt. This starts a Google authentication activity, returning the user to the custom DPC upon successful authentication. The user can also skip this process. In this case, a Managed Google Play account will be added to the device. This option can be configured using googleAuthenticationOptions.
  5. Finalize Enrollment: The AMAPI SDK notifies the custom DPC of the enrollment result.
  6. Enable Google services: Once a user's device with the Managed Google Account is compliant with enterprise policies, the EMM must call Devices.setState(). This action enables access to Google services for the account on the device. Without this call, the Play Store and other Google services won't function.

Account Setup - sample code

  1. To initiate an account setup attempt, the calling app can use AccountSetupClient and call either the startAccountSetup() or startAccountSetupFuture() method. For an example implementation, see the following code sample:

    // Create AccountSetupClient
    val client = AccountSetupClientFactory.create(
        this,
        activityResultRegistry
    )
    lifecycle.addObserver(client.lifecycleObserver)
    
    // Create adminComponent
    val notificationReceiver = ComponentName(this, AccountSetupNotificationReceiver::class.java)
    // Helper method to get enrollment token created with Play EMM API
    val enrollmentToken = getEnrollmentToken()
    val request =
              StartAccountSetupRequest.builder()
                  .setEnrollmentToken(enteredText)
                  .setNotificationReceiverServiceComponentName(notificationReceiver)
                  .setAdminComponentName(
                      ComponentName(this, com.example.dpc.DeviceAdminReceiver::class.java))
                  .build()
    try {
        val accountSetupAttempt = client.startAccountSetup(request)
        // handle attempt
    } catch (e: Exception) {
        // handle exception
    }
      ```
    
  2. Implement AccountSetupListener interface and provide an implementation for how to handle the received status updates.

  3. Extend NotificationReceiverService and provide the AccountSetupListener instance created in step 2 by overriding getAccountSetupListener().

    // Handles account setup changes
    class AccountSetupNotificationReceiver :
          NotificationReceiverService(),
          AccountSetupListener {
    
        override fun getAccountSetupListener(): AccountSetupListener = this
    
        override fun onAccountSetupChanged(accountSetupAttempt:
      AccountSetupAttempt) {
    
            when (accountSetupAttempt.state.kind) {
                StateCase.ADDED_ACCOUNT -> {
                    val enterpriseAccount = state.addedAccount()
                    val userId = enterpriseAccount.userId
                    val deviceId = enterpriseAccount.deviceId
                    // Handle account added state.
    
                }
                StateCase.AUTHENTICATION_ACTIVITY_LAUNCH_REQUIRED -> {
                    val request = LaunchAuthenticationActivityRequest.builder()
                .setAccountSetupAttempt(accountSetupAttempt)
                .build();
                    // Send the attempt to the foreground activity to call:
                    accountSetupClient.launchAuthenticationActivity(request)
                }
                StateCase.ACCOUNT_SETUP_ERROR -> {
                    // Handle error state.
                    val failureReason = state.accountSetupError().failureReason
                }
                else -> {
                    // Handle unknown account setup attempt state.
                }
            }
        }
    }
    
      ```
    
  4. Add the extended NotificationReceiverService class to your AndroidManifest.xml and verify it is exported.

      <application>
        <service
            android:name = ".accountsetup.AccountSetupNotificationReceiver"
            android:exported = "true" />
      </application>
    

    If your app targets SDK 30 or later, then a queries element is needed in the AndroidManifest.xml to specify that it will interact with ADP.

      <queries>
        <package android:name="com.google.android.apps.work.clouddpc" />
      </queries>
    

Testing guidance

This section provides a set of guidelines and best practices for testing your implementation.

Test PrepareEnvironment

  1. Get Device's Current State: The EMM runs

    adb shell dumpsys package com.google.android.apps.work.clouddpc | grep versionName
    

    to get the version of the Android Device Policy present on the device. If the Android Device Policy is not installed, an empty output is expected.

  2. Integrate PrepareEnvironment: The custom DPC invokes prepareEnvironment API in the AMAPI SDK, passing the correct request.

  3. Await PrepareEnvironment result: The custom DPC waits for the prepareEnvironment to complete.

  4. Confirm PrepareEnvironment success: On completion, EMM runs again

    adb shell dumpsys package com.google.android.apps.work.clouddpc | grep versionName
    

    This time the Android Device Policy version should be higher than in step 1.

Test Google Account authentication

  1. Create test enterprise: The EMM creates a test domain Google enterprise linked to a test EMM, with enterprises.generateSignupUrl.
  2. Enable Google authentication: The EMM enables Google authentication for the test enterprise following these instructions in the Google Admin console.
  3. Create Enrollment Token: The EMM creates an enrollment token using the Play EMM API with type userDevice.
  4. Initiate Enrollment: The custom DPC invokes the startAccountSetup API in the AMAPI SDK, passing the enrollment token.
  5. Launch activity required: The AMAPI SDK notifies the custom DPC that an activity must be launched to authenticate the user.
  6. Authenticate the user: The custom DPC invokes launchAuthenticationActivity to start the activity. The user authenticates with a Managed Google Account (part of the enterprise created in step 1).
  7. Finalize Enrollment: The AMAPI SDK notifies the custom DPC of the enrollment result.

Test skipping Google authentication

We will use the previously described setup.

This time, in step 7, the user presses Skip instead of authenticating with their Google Account. The enrollment completes successfully, with a service account on the device (i.e. the AuthenticationType is Anonymous).

Test userless devices

The improved custom DPC enrollment flow utilizes the followeing steps, when Google authentication is disabled:

  1. Create a test enterprise: This can be the same enterprise as created previously.
  2. Create Enrollment Token: The EMM creates an enrollmenttoken using the Play EMM API with type userlessDevice.
  3. Initiate Enrollment: The custom DPC invokes the startAccountSetup API in the AMAPI SDK, passing the enrollment token.
  4. Finalize Enrollment: The AMAPI SDK notifies the custom DPC of the enrollment result.