### Install ed command-line utility Source: https://context7.com/googlesamples/android-testdpc/llms.txt Installs the 'ed' command-line utility, which is required for build.sh patching. Use apt-get for Debian/Ubuntu and brew for macOS. ```bash sudo apt-get install ed # Debian/Ubuntu brew install ed # macOS ``` -------------------------------- ### Install Test DPC APK on Device Source: https://context7.com/googlesamples/android-testdpc/llms.txt Installs the built Test DPC APK onto a connected Android device using ADB. The -r flag allows for reinstallation if the app is already present. ```bash adb install -r bazel-bin/testdpc.apk ``` -------------------------------- ### Block Uninstallation and Install Existing Packages using Java Source: https://context7.com/googlesamples/android-testdpc/llms.txt Prevent users from uninstalling specific apps with setUninstallBlocked, or install pre-existing system packages using installExistingPackage. Verify blocking status with isUninstallBlocked. ```java // Block uninstallation of a required app gateway.setUninstallBlocked("com.example.corpapp", true, (v) -> Log.i(TAG, "Uninstall blocked"), (e) -> Log.e(TAG, "Failed", e)); // Install a system/pre-existing package into the managed profile gateway.installExistingPackage("com.google.android.apps.docs", (v) -> Log.i(TAG, "Package installed"), (e) -> Log.e(TAG, "Install failed", e)); // Check boolean blocked = gateway.isUninstallBlocked("com.example.corpapp"); ``` -------------------------------- ### Set up Android SDK Environment for Bazel Build Source: https://context7.com/googlesamples/android-testdpc/llms.txt Configures the ANDROID_HOME environment variable, which is a prerequisite for building Test DPC using Bazel. Ensure the path points to your Android SDK installation. ```bash # Prerequisites: Set ANDROID_HOME export ANDROID_HOME=/path/to/android/sdk ``` -------------------------------- ### removeUser / switchUser / startUserInBackground Source: https://context7.com/googlesamples/android-testdpc/llms.txt Manages the lifecycle of managed users. These methods allow for removing, switching to, or starting users in the background. ```APIDOC ## removeUser / switchUser / startUserInBackground — User Lifecycle Controls the lifecycle of managed users. `removeUser` deletes the user; `switchUser` brings it to foreground; `startUserInBackground` starts it without switching. ### Java API ```java // Remove a user by serial number long serialNumber = 10L; UserHandle user = gateway.getUserHandle(serialNumber); gateway.removeUser(user, (v) -> Log.i(TAG, "Removed user " + serialNumber), (e) -> Log.e(TAG, "Remove failed", e)); // Start user in background gateway.startUserInBackground(user, (resultCode) -> Log.i(TAG, "Start result: " + resultCode), (e) -> Log.e(TAG, "Start failed", e)); ``` ### ADB equivalents ```bash adb shell dumpsys activity --user 0 service com.afwsamples.testdpc switch-user 10 adb shell dumpsys activity --user 0 service com.afwsamples.testdpc remove-user 10 adb shell dumpsys activity --user 0 service com.afwsamples.testdpc start-user-in-background 10 ``` ``` -------------------------------- ### Create a Managed User Source: https://context7.com/googlesamples/android-testdpc/llms.txt Creates a new managed user on the device. Flags can be combined to customize user creation, such as making the user ephemeral or skipping the setup wizard. Requires Device Owner privileges. ```java gateway.createAndManageUser( "WorkUser", // display name DevicePolicyManager.MAKE_USER_EPHEMERAL, // flags (UserHandle newUser) -> { Log.i(TAG, "User created: " + newUser); // Switch to the new user gateway.switchUser(newUser, (v) -> Log.i(TAG, "Switched to " + newUser), (e) -> Log.e(TAG, "Switch failed", e)); }, (Exception e) -> Log.e(TAG, "User creation failed", e)); ``` ```bash adb shell dumpsys activity --user 0 service com.afwsamples.testdpc \ create-user "WorkUser" --flags 4 # Output: User created: UserHandle{10} serial=10 ``` -------------------------------- ### QR Code Provisioning for Device Owner (Android N+) Source: https://context7.com/googlesamples/android-testdpc/llms.txt Configures TestDPC as Device Owner using a QR code during device setup. This JSON payload contains necessary provisioning details. ```json { "android.app.extra.PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME": "com.afwsamples.testdpc/com.afwsamples.testdpc.DeviceAdminReceiver", "android.app.extra.PROVISIONING_DEVICE_ADMIN_SIGNATURE_CHECKSUM": "gJD2YwtOiWJHkSMkkIfLRlj-quNqG1fb6v100QmzM9w=", "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION": "https://testdpc-latest-apk.appspot.com" } ``` -------------------------------- ### setUninstallBlocked / installExistingPackage — Package Install Control Source: https://context7.com/googlesamples/android-testdpc/llms.txt Prevents users from uninstalling managed apps and allows installing packages that already exist in the device's app repository. Includes a method to check if uninstallation is blocked. ```APIDOC ## setUninstallBlocked / installExistingPackage — Package Install Control ### Description Prevents users from uninstalling managed apps, or installs packages that already exist in the device's app repository. ### Method `gateway.setUninstallBlocked(String packageName, boolean blocked, Consumer onSuccess, Consumer onError)` `gateway.installExistingPackage(String packageName, Consumer onSuccess, Consumer onError)` `gateway.isUninstallBlocked(String packageName)` ### Parameters #### `setUninstallBlocked` - **packageName** (String) - Required - The package name to block or unblock uninstallation for. - **blocked** (boolean) - Required - `true` to block uninstallation, `false` to allow. - **onSuccess** (Consumer) - Callback for successful operation. - **onError** (Consumer) - Callback for errors. #### `installExistingPackage` - **packageName** (String) - Required - The package name of the existing system/pre-existing app to install. - **onSuccess** (Consumer) - Callback for successful operation. - **onError** (Consumer) - Callback for errors. #### `isUninstallBlocked` - **packageName** (String) - Required - The package name to check. ### Request Example (Java) ```java // Block uninstallation of a required app gateway.setUninstallBlocked("com.example.corpapp", true, (v) -> Log.i(TAG, "Uninstall blocked"), (e) -> Log.e(TAG, "Failed", e)); // Install a system/pre-existing package into the managed profile gateway.installExistingPackage("com.google.android.apps.docs", (v) -> Log.i(TAG, "Package installed"), (e) -> Log.e(TAG, "Install failed", e)); // Check boolean blocked = gateway.isUninstallBlocked("com.example.corpapp"); ``` ### Request Example (adb) ```bash adb shell dumpsys activity --user 0 service com.afwsamples.testdpc \ set-uninstall-blocked com.example.corpapp true adb shell dumpsys activity --user 0 service com.afwsamples.testdpc \ is-uninstall-blocked com.example.corpapp ``` ### Response Example (adb output) ``` true ``` ``` -------------------------------- ### Suspend and Hide Apps using Java Source: https://context7.com/googlesamples/android-testdpc/llms.txt Use setPackagesSuspended to make apps unusable but installed, and setApplicationHidden to remove them from the user's view. Check their state with isPackageSuspended and isApplicationHidden. ```java String[] packagesToSuspend = {"com.example.game", "com.social.network"}; // Suspend packages (grey out icons, block launch) gateway.setPackagesSuspended(packagesToSuspend, true, (failedPackages) -> Log.i(TAG, "Suspended (except: " + Arrays.toString(failedPackages) + ")"), (e) -> Log.e(TAG, "Suspend failed", e)); // Hide a package entirely gateway.setApplicationHidden("com.social.network", true, (v) -> Log.i(TAG, "App hidden"), (e) -> Log.e(TAG, "Hide failed", e)); // Check state boolean suspended = gateway.isPackageSuspended("com.example.game"); boolean hidden = gateway.isApplicationHidden("com.social.network"); ``` -------------------------------- ### COSU XML Configuration Source: https://context7.com/googlesamples/android-testdpc/llms.txt Configures a fully automated COSU (kiosk) setup using an XML file. The config is parsed at provisioning time to download apps, enable system apps, hide others, apply user restrictions, and configure global settings. ```APIDOC ## COSU XML Configuration — CosuConfig Configures a fully automated COSU (kiosk) setup using an XML file. The config is parsed at provisioning time to download apps, enable system apps, hide others, apply user restrictions, and configure global settings. ### XML Configuration Example ```xml ``` ### Java Code Example ```java // Load and apply COSU config from an InputStream InputStream in = context.getAssets().open("cosu_config.xml"); CosuConfig config = CosuConfig.createConfig(context, in); if (config != null) { boolean success = config.applyPolicies( DeviceAdminReceiver.getComponentName(context)); config.initiateDownloadAndInstall(handler); // async download & install Log.i(TAG, "Mode: " + config.getMode()); // "cosu" Log.i(TAG, "Kiosk apps: " + Arrays.toString(config.getKioskApps())); } ``` ``` -------------------------------- ### COSU XML Configuration Source: https://context7.com/googlesamples/android-testdpc/llms.txt Defines the configuration for a fully automated COSU (kiosk) setup. This XML file is parsed at provisioning time to manage app downloads, system app states, user restrictions, and global settings. ```xml ``` -------------------------------- ### Control Managed User Lifecycle Source: https://context7.com/googlesamples/android-testdpc/llms.txt Manages the lifecycle of managed users. Use `removeUser` to delete a user, `switchUser` to bring a user to the foreground, and `startUserInBackground` to start a user without switching to it. Requires the user's serial number. ```java // Remove a user by serial number long serialNumber = 10L; UserHandle user = gateway.getUserHandle(serialNumber); gateway.removeUser(user, (v) -> Log.i(TAG, "Removed user " + serialNumber), (e) -> Log.e(TAG, "Remove failed", e)); // Start user in background gateway.startUserInBackground(user, (resultCode) -> Log.i(TAG, "Start result: " + resultCode), (e) -> Log.e(TAG, "Start failed", e)); ``` ```bash adb shell dumpsys activity --user 0 service com.afwsamples.testdpc switch-user 10 adb shell dumpsys activity --user 0 service com.afwsamples.testdpc remove-user 10 adb shell dumpsys activity --user 0 service com.afwsamples.testdpc start-user-in-background 10 ``` -------------------------------- ### Set Organization Branding and Lock Screen Info Source: https://context7.com/googlesamples/android-testdpc/llms.txt Sets the organization name displayed in device settings and custom text shown on the lock screen. Includes examples for setting and reading back these values. ```java // Set organization name shown in Settings > Security gateway.setOrganizationName("Acme Corporation", (v) -> Log.i(TAG, "Org name set"), (e) -> Log.e(TAG, "Failed", e)); // Set lock screen info message gateway.setDeviceOwnerLockScreenInfo("This device is managed by Acme IT. Call 1-800-ACME.", (v) -> Log.i(TAG, "Lock screen info set"), (e) -> Log.e(TAG, "Failed", e)); // Read back CharSequence orgName = gateway.getOrganizationName(); CharSequence lockInfo = gateway.getDeviceOwnerLockScreenInfo(); ``` ```bash adb shell dumpsys activity --user 0 service com.afwsamples.testdpc \ set-organization-name "Acme Corporation" adb shell dumpsys activity --user 0 service com.afwsamples.testdpc \ set-device-owner-lockscreen-info "Managed by Acme IT. Call 1-800-ACME." adb shell dumpsys activity --user 0 service com.afwsamples.testdpc get-organization-name # Output: Acme Corporation ``` -------------------------------- ### DevicePolicyManagerGateway Construction and Usage Source: https://context7.com/googlesamples/android-testdpc/llms.txt Demonstrates constructing and using the `DevicePolicyManagerGatewayImpl` for interacting with `DevicePolicyManager` APIs. It supports async callbacks and scoping to the parent profile. ```java import com.afwsamples.testdpc.DevicePolicyManagerGatewayImpl; import java.util.function.Consumer; // Standard construction from a Context DevicePolicyManagerGateway gateway = new DevicePolicyManagerGatewayImpl(context); // For parent-profile scoped operations (from managed profile) DevicePolicyManagerGateway parentGateway = DevicePolicyManagerGatewayImpl.forParentProfile(context); // Check owner type boolean isDO = gateway.isDeviceOwnerApp(); // true if Device Owner boolean isPO = gateway.isProfileOwnerApp(); // true if Profile Owner boolean isCOPE = gateway.isOrganizationOwnedDeviceWithManagedProfile(); // Dump state via ADB // adb shell dumpsys activity --user 0 service com.afwsamples.testdpc dump // isDeviceOwner: true // isProfileOwner: false // isOrganizationOwnedDeviceWithManagedProfile: false // isDeviceIdAttestationSupported: true ``` -------------------------------- ### Import Test DPC in Android Studio Source: https://context7.com/googlesamples/android-testdpc/llms.txt Instructions for importing the Test DPC project into Android Studio using the Bazel for Android Studio plugin. Requires specifying the build file directory and a project view file. ```text # Import in Android Studio (requires Bazel for Android Studio plugin) # Select the directory containing the BUILD file as project root # Use "scripts/ij.bazelproject" as the project view file # Create a Run Configuration: type=Bazel Command, target=//:testdpc ``` -------------------------------- ### Handle onProfileProvisioningComplete Event Source: https://context7.com/googlesamples/android-testdpc/llms.txt This method is called when profile provisioning is complete on pre-O devices. It performs post-provisioning operations and launches an activity. ```java // Called when provisioning is complete (pre-O devices) @Override public void onProfileProvisioningComplete(Context context, Intent intent) { PostProvisioningTask task = new PostProvisioningTask(context); task.performPostProvisioningOperations(intent); Intent launchIntent = task.getPostProvisioningLaunchIntent(intent); context.startActivity(launchIntent); } ``` -------------------------------- ### QR Code Provisioning JSON Configuration Source: https://github.com/googlesamples/android-testdpc/blob/master/README.md Use this JSON to generate a QR code for provisioning a device as a Device Owner. Ensure the package download location points to a valid APK. ```json { "android.app.extra.PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME": "com.afwsamples.testdpc/com.afwsamples.testdpc.DeviceAdminReceiver", "android.app.extra.PROVISIONING_DEVICE_ADMIN_SIGNATURE_CHECKSUM": "gJD2YwtOiWJHkSMkkIfLRlj-quNqG1fb6v100QmzM9w=", "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION": "https://testdpc-latest-apk.appspot.com" } ``` -------------------------------- ### setPackagesSuspended / setApplicationHidden — App Visibility Source: https://context7.com/googlesamples/android-testdpc/llms.txt Allows suspending apps to make them unusable but installed, or hiding them entirely from the user. Includes methods to check the suspended and hidden states of packages. ```APIDOC ## setPackagesSuspended / setApplicationHidden — App Visibility ### Description Suspends apps (making them unusable but installed) or hides them entirely from the user. ### Method `gateway.setPackagesSuspended(String[] packagesToSuspend, boolean suspend, Consumer onSuccess, Consumer onError)` `gateway.setApplicationHidden(String packageName, boolean hidden, Consumer onSuccess, Consumer onError)` `gateway.isPackageSuspended(String packageName)` `gateway.isApplicationHidden(String packageName)` ### Parameters #### `setPackagesSuspended` - **packagesToSuspend** (String[]) - Required - An array of package names to suspend. - **suspend** (boolean) - Required - `true` to suspend, `false` to unsuspend. - **onSuccess** (Consumer) - Callback for successful operation, receives a list of failed packages. - **onError** (Consumer) - Callback for errors. #### `setApplicationHidden` - **packageName** (String) - Required - The package name to hide or unhide. - **hidden** (boolean) - Required - `true` to hide, `false` to unhide. - **onSuccess** (Consumer) - Callback for successful operation. - **onError** (Consumer) - Callback for errors. #### `isPackageSuspended` - **packageName** (String) - Required - The package name to check. #### `isApplicationHidden` - **packageName** (String) - Required - The package name to check. ### Request Example (Java) ```java String[] packagesToSuspend = {"com.example.game", "com.social.network"}; // Suspend packages (grey out icons, block launch) gateway.setPackagesSuspended(packagesToSuspend, true, (failedPackages) -> Log.i(TAG, "Suspended (except: " + Arrays.toString(failedPackages) + ")"), (e) -> Log.e(TAG, "Suspend failed", e)); // Hide a package entirely gateway.setApplicationHidden("com.social.network", true, (v) -> Log.i(TAG, "App hidden"), (e) -> Log.e(TAG, "Hide failed", e)); // Check state boolean suspended = gateway.isPackageSuspended("com.example.game"); boolean hidden = gateway.isApplicationHidden("com.social.network"); ``` ### Request Example (adb) ```bash adb shell dumpsys activity --user 0 service com.afwsamples.testdpc \ set-suspended-packages true com.example.game com.social.network adb shell dumpsys activity --user 0 service com.afwsamples.testdpc \ is-suspended-packages com.example.game com.social.network ``` ### Response Example (adb output) ``` com.example.game: SUSPENDED com.social.network: SUSPENDED ``` ``` -------------------------------- ### Configure Kiosk Mode using ADB Source: https://context7.com/googlesamples/android-testdpc/llms.txt Manage kiosk mode settings via ADB. Use set-lock-task-packages to define allowed apps, set-lock-task-features to configure UI elements, and is-lock-task-permitted to check app permissions. ```bash adb shell dumpsys activity --user 0 service com.afwsamples.testdpc \ set-lock-task-packages com.example.kioskapp adb shell dumpsys activity --user 0 service com.afwsamples.testdpc \ set-lock-task-features 3 # HOME | NOTIFICATIONS adb shell dumpsys activity --user 0 service com.afwsamples.testdpc \ is-lock-task-permitted com.example.kioskapp ``` ```text # Output: com.example.kioskapp: PERMITTED ``` -------------------------------- ### Build Test DPC APK Source: https://context7.com/googlesamples/android-testdpc/llms.txt Builds the Test DPC APK using Bazel. The output APK will be located at bazel-bin/testdpc.apk. Alternatively, the convenience script ./build.sh can be used. ```bash bazel build testdpc # Output APK: bazel-bin/testdpc.apk # Or use the convenience script ./build.sh ``` -------------------------------- ### Get ComponentName for DPM API calls Source: https://context7.com/googlesamples/android-testdpc/llms.txt Returns the ComponentName for the DeviceAdminReceiver, which is necessary for many Device Policy Manager (DPM) API calls. Returns null if the context is not a Device Owner or Profile Owner. ```java // Get the ComponentName for DPM API calls public static ComponentName getComponentName(Context context) { if (Util.isDeviceOwner(context) || Util.isProfileOwner(context)) { return new ComponentName(context, DeviceAdminReceiver.class); } return null; // null for delegates and role holders } ``` -------------------------------- ### Apply COSU Configuration from InputStream Source: https://context7.com/googlesamples/android-testdpc/llms.txt Loads and applies a COSU configuration from an InputStream. Ensure the configuration is valid before applying policies and initiating app downloads. ```java // Load and apply COSU config from an InputStream InputStream in = context.getAssets().open("cosu_config.xml"); CosuConfig config = CosuConfig.createConfig(context, in); if (config != null) { boolean success = config.applyPolicies( DeviceAdminReceiver.getComponentName(context)); config.initiateDownloadAndInstall(handler); // async download & install Log.i(TAG, "Mode: " + config.getMode()); // "cosu" Log.i(TAG, "Kiosk apps: " + Arrays.toString(config.getKioskApps())); } ``` -------------------------------- ### Block Uninstallation using ADB Source: https://context7.com/googlesamples/android-testdpc/llms.txt Manage package uninstallation blocking via ADB. Use set-uninstall-blocked to enable or disable blocking, and is-uninstall-blocked to check the current state. ```bash adb shell dumpsys activity --user 0 service com.afwsamples.testdpc \ set-uninstall-blocked com.example.corpapp true adb shell dumpsys activity --user 0 service com.afwsamples.testdpc \ is-uninstall-blocked com.example.corpapp ``` ```text # Output: true ``` -------------------------------- ### Provision Device Owner via ADB Source: https://context7.com/googlesamples/android-testdpc/llms.txt Provisions TestDPC as Device Owner on a device. Requires a factory reset first. Use `dumpsys` to verify provisioning. ```bash # Factory reset the device first, then: adb shell dpm set-device-owner com.afwsamples.testdpc/.DeviceAdminReceiver # Expected output: Success: Device owner set to package com.afwsamples.testdpc # Verify provisioning adb shell dumpsys activity --user 0 service com.afwsamples.testdpc dump # Expected output: # isDeviceOwner: true # isProfileOwner: false # isOrganizationOwnedDeviceWithManagedProfile: false ``` -------------------------------- ### Enable and Retrieve Security Logs (Java) Source: https://context7.com/googlesamples/android-testdpc/llms.txt Enables security logging for events like key access, unlock attempts, and ADB commands, and provides callbacks for retrieving these logs. This feature is for Device Owner and affiliated users only. ```java // Enable security logging gateway.setSecurityLoggingEnabled(true, (v) -> Log.i(TAG, "Security logging enabled"), (e) -> Log.e(TAG, "Failed", e)); // In DeviceAdminReceiver.onSecurityLogsAvailable(): @Override public void onSecurityLogsAvailable(Context context, Intent intent) { List events = gateway.retrieveSecurityLogs(); for (SecurityEvent event : events) { Log.i(TAG, "Tag=" + event.getTag() + " data=" + event.getData()); } // Also retrieve events from before last reboot List preReboot = gateway.retrievePreRebootSecurityLogs(); } ``` -------------------------------- ### Enable and Retrieve Security Logs (ADB) Source: https://context7.com/googlesamples/android-testdpc/llms.txt Enables security logging and retrieves security logs using ADB shell commands. This is useful for auditing security-sensitive events on the device. ```bash adb shell dumpsys activity --user 0 service com.afwsamples.testdpc \ set-security-logging-enabled true adb shell dumpsys activity --user 0 service com.afwsamples.testdpc retrieve-security-logs # Output: # 5 events: # 10001: TAG_ADB_SHELL_CMD (05-22 14:30:01.123): adb shell dumpsys ... ``` -------------------------------- ### Enable and Retrieve Network Logs (Java) Source: https://context7.com/googlesamples/android-testdpc/llms.txt Enables network logging for DNS and TCP connection events and provides a callback for retrieving these logs. This feature is available for Device Owner and affiliated users only. ```java // Enable network logging gateway.setNetworkLoggingEnabled(true, (v) -> Log.i(TAG, "Network logging enabled"), (e) -> Log.e(TAG, "Failed", e)); // In DeviceAdminReceiver.onNetworkLogsAvailable(): @Override public void onNetworkLogsAvailable(Context ctx, Intent intent, long batchToken, int count) { List events = gateway.retrieveNetworkLogs(batchToken); for (NetworkEvent event : events) { if (event instanceof DnsEvent) { DnsEvent dns = (DnsEvent) event; Log.i(TAG, "DNS: " + dns.getHostname() + " -> " + dns.getInetAddresses()); } else if (event instanceof ConnectEvent) { ConnectEvent conn = (ConnectEvent) event; Log.i(TAG, "TCP: " + conn.getInetAddress() + ":" + conn.getPort()); } } } ``` -------------------------------- ### Enable and Retrieve Network Logs (ADB) Source: https://context7.com/googlesamples/android-testdpc/llms.txt Enables network logging and retrieves network logs using ADB shell commands. This is useful for debugging network activity on the device. ```bash adb shell dumpsys activity --user 0 service com.afwsamples.testdpc \ set-network-logging-enabled true adb shell dumpsys activity --user 0 service com.afwsamples.testdpc \ retrieve-network-logs 1234567890 # Output: # 3 events: # 0:DnsEvent id=1 pkg=com.example.app hostname=api.example.com addresses=/93.184.216.34 # 1:ConnectEvent id=2 pkg=com.example.app address=/93.184.216.34 port=443 ``` -------------------------------- ### Configure Kiosk Mode Packages and Features using Java Source: https://context7.com/googlesamples/android-testdpc/llms.txt Lock the device to specific apps using setLockTaskPackages and control system UI features with setLockTaskFeatures. Check permissions with isLockTaskPermitted and retrieve current settings with getLockTaskPackages/getLockTaskFeatures. ```java // Allow only a kiosk app to run String[] kioskApps = {"com.example.kioskapp"}; gateway.setLockTaskPackages(kioskApps, (v) -> Log.i(TAG, "Lock task packages set"), (e) -> Log.e(TAG, "Failed", e)); // Enable home button and notifications in kiosk mode; disable everything else int features = DevicePolicyManager.LOCK_TASK_FEATURE_HOME | DevicePolicyManager.LOCK_TASK_FEATURE_NOTIFICATIONS; gateway.setLockTaskFeatures(features, (v) -> Log.i(TAG, "Features set"), (e) -> Log.e(TAG, "Failed", e)); // Then in the kiosk app, start lock task mode: // activity.startLockTask(); // Check permissions boolean permitted = gateway.isLockTaskPermitted("com.example.kioskapp"); String[] currentPkgs = gateway.getLockTaskPackages(); int currentFeatures = gateway.getLockTaskFeatures(); ``` -------------------------------- ### Control Hardware Policies Source: https://context7.com/googlesamples/android-testdpc/llms.txt Restricts hardware-level device capabilities such as camera, screen capture, and status bar. Ensure the device is in kiosk mode or has appropriate owner privileges for certain restrictions. ```java // Disable camera for the managed profile gateway.setCameraDisabled(true, (v) -> Log.i(TAG, "Camera disabled"), (e) -> Log.e(TAG, "Failed to disable camera", e)); // Disable screen capture gateway.setScreenCaptureDisabled(true, (v) -> Log.i(TAG, "Screen capture disabled"), (e) -> Log.e(TAG, "Failed", e)); // Disable status bar (kiosk mode, Device Owner / Managed Profile Owner API 23+) gateway.setStatusBarDisabled(true, (v) -> Log.i(TAG, "Status bar disabled"), (e) -> Log.e(TAG, "Failed", e)); // Check camera state boolean disabledByThisAdmin = gateway.getCameraDisabled(); boolean disabledByAnyAdmin = gateway.getCameraDisabledByAnyAdmin(); ``` ```bash adb shell dumpsys activity --user 0 service com.afwsamples.testdpc set-camera-disabled true adb shell dumpsys activity --user 0 service com.afwsamples.testdpc get-camera-disabled # Output: # By com.afwsamples.testdpc/.DeviceAdminReceiver: true # By any admin: true ``` -------------------------------- ### Delegate Admin Scopes using Java Source: https://context7.com/googlesamples/android-testdpc/llms.txt Grant specific Device Policy Manager capabilities to a non-DPC app using setDelegatedScopes. Query delegated scopes with getDelegatedScopes and getDelegatePackages. ```java List scopes = Arrays.asList( DevicePolicyManager.DELEGATION_CERT_INSTALL, DevicePolicyManager.DELEGATION_APP_RESTRICTIONS); gateway.setDelegatedScopes("com.example.delegateapp", scopes, (v) -> Log.i(TAG, "Scopes delegated"), (e) -> Log.e(TAG, "Delegation failed", e)); // Query what's delegated to an app List currentScopes = gateway.getDelegatedScopes("com.example.delegateapp"); // Query which apps have a specific delegation List certDelegates = gateway.getDelegatePackages(DevicePolicyManager.DELEGATION_CERT_INSTALL); ``` -------------------------------- ### Delegate Admin Scopes using ADB Source: https://context7.com/googlesamples/android-testdpc/llms.txt Manage delegated admin scopes via ADB. Use set-delegated-scopes to assign scopes and get-delegated-scopes to retrieve them. ```bash adb shell dumpsys activity --user 0 service com.afwsamples.testdpc \ set-delegated-scopes com.example.delegateapp \ android.app.admin.DELEGATION_CERT_INSTALL \ android.app.admin.DELEGATION_APP_RESTRICTIONS adb shell dumpsys activity --user 0 service com.afwsamples.testdpc \ get-delegated-scopes com.example.delegateapp ``` ```text # Output: # 2 scopes: # android.app.admin.DELEGATION_CERT_INSTALL # android.app.admin.DELEGATION_APP_RESTRICTIONS ``` -------------------------------- ### Set Profile Owner (COPE) via ADB Source: https://context7.com/googlesamples/android-testdpc/llms.txt Creates a managed work profile on a corporate-owned device and marks it as organization-owned. This involves launching the app, finding the user ID, and then marking the profile. ```bash # Step 1: Launch "Set up TestDPC" app on the device and create the managed profile, skip adding account # Step 2: Find the managed profile user ID (usually user 10) adb shell pm list users # Output: Users: UserInfo{0:Owner:...} UserInfo{10:Work profile:...} # Step 3: Mark as COPE adb shell dpm mark-profile-owner-on-organization-owned-device \ --user 10 com.afwsamples.testdpc/.DeviceAdminReceiver # Expected output: Success ``` -------------------------------- ### createAndManageUser Source: https://context7.com/googlesamples/android-testdpc/llms.txt Creates a new managed user on the device. This method is available only to Device Owners and supports various flags for user creation. ```APIDOC ## createAndManageUser — Create a Managed User Creates a new managed user on the device (Device Owner only). Flags can combine `DevicePolicyManager.MAKE_USER_EPHEMERAL`, `SKIP_SETUP_WIZARD`, etc. ### Java API ```java gateway.createAndManageUser( "WorkUser", // display name DevicePolicyManager.MAKE_USER_EPHEMERAL, // flags (UserHandle newUser) -> { Log.i(TAG, "User created: " + newUser); // Switch to the new user gateway.switchUser(newUser, (v) -> Log.i(TAG, "Switched to " + newUser), (e) -> Log.e(TAG, "Switch failed", e)); }, (Exception e) -> Log.e(TAG, "User creation failed", e)); ``` ### ADB equivalent ```bash adb shell dumpsys activity --user 0 service com.afwsamples.testdpc \ create-user "WorkUser" --flags 4 # Output: User created: UserHandle{10} serial=10 ``` ``` -------------------------------- ### Set Device Owner via ADB Source: https://github.com/googlesamples/android-testdpc/blob/master/README.md Command to set the Test DPC app as the Device Owner on a fully managed device. This requires the device to be in an unprovisioned state. ```bash adb shell dpm set-device-owner com.afwsamples.testdpc/.DeviceAdminReceiver ``` -------------------------------- ### Hardware Policy Controls Source: https://context7.com/googlesamples/android-testdpc/llms.txt Controls hardware-level policies that restrict device capabilities such as camera, screen capture, and status bar. ```APIDOC ## setCameraDisabled / setScreenCaptureDisabled / setStatusBarDisabled — Hardware Policy ### Description Controls hardware-level policies that restrict device capabilities. ### Method ```java gateway.setCameraDisabled(disabled, onSuccess, onError); gateway.setScreenCaptureDisabled(disabled, onSuccess, onError); gateway.setStatusBarDisabled(disabled, onSuccess, onError); boolean getCameraDisabled(); boolean getCameraDisabledByAnyAdmin(); ``` ### Parameters #### `setCameraDisabled`, `setScreenCaptureDisabled`, `setStatusBarDisabled` Parameters - **disabled** (boolean) - `true` to disable the feature, `false` to enable. - **onSuccess** (Consumer) - Callback for successful operation. - **onError** (Consumer) - Callback for operation failure. ### Request Example (Java) ```java // Disable camera for the managed profile gateway.setCameraDisabled(true, (v) -> Log.i(TAG, "Camera disabled"), (e) -> Log.e(TAG, "Failed to disable camera", e)); // Disable screen capture gateway.setScreenCaptureDisabled(true, (v) -> Log.i(TAG, "Screen capture disabled"), (e) -> Log.e(TAG, "Failed", e)); // Disable status bar (kiosk mode, Device Owner / Managed Profile Owner API 23+) gateway.setStatusBarDisabled(true, (v) -> Log.i(TAG, "Status bar disabled"), (e) -> Log.e(TAG, "Failed", e)); // Check camera state boolean disabledByThisAdmin = gateway.getCameraDisabled(); boolean disabledByAnyAdmin = gateway.getCameraDisabledByAnyAdmin(); ``` ### Request Example (adb shell) ```bash # Disable camera adb shell dumpsys activity --user 0 service com.afwsamples.testdpc set-camera-disabled true # Get camera disabled state adb shell dumpsys activity --user 0 service com.afwsamples.testdpc get-camera-disabled # Output: # By com.afwsamples.testdpc/.DeviceAdminReceiver: true # By any admin: true ``` ``` -------------------------------- ### Network Logging Source: https://context7.com/googlesamples/android-testdpc/llms.txt Captures DNS and TCP connection events from the device (Device Owner, affiliated users only). ```APIDOC ## Logging & Diagnostics ### setNetworkLoggingEnabled / retrieveNetworkLogs — Network Logging Captures DNS and TCP connection events from the device (Device Owner, affiliated users only). ### Java Code Example ```java // Enable network logging gateway.setNetworkLoggingEnabled(true, (v) -> Log.i(TAG, "Network logging enabled"), (e) -> Log.e(TAG, "Failed", e)); // In DeviceAdminReceiver.onNetworkLogsAvailable(): @Override public void onNetworkLogsAvailable(Context ctx, Intent intent, long batchToken, int count) { List events = gateway.retrieveNetworkLogs(batchToken); for (NetworkEvent event : events) { if (event instanceof DnsEvent) { DnsEvent dns = (DnsEvent) event; Log.i(TAG, "DNS: " + dns.getHostname() + " -> " + dns.getInetAddresses()); } else if (event instanceof ConnectEvent) { ConnectEvent conn = (ConnectEvent) event; Log.i(TAG, "TCP: " + conn.getInetAddress() + ":" + conn.getPort()); } } } ``` ### ADB Shell Example ```bash adb shell dumpsys activity --user 0 service com.afwsamples.testdpc \ set-network-logging-enabled true adb shell dumpsys activity --user 0 service com.afwsamples.testdpc \ retrieve-network-logs 1234567890 # Output: # 3 events: # 0:DnsEvent id=1 pkg=com.example.app hostname=api.example.com addresses=/93.184.216.34 # 1:ConnectEvent id=2 pkg=com.example.app address=/93.184.216.34 port=443 ``` ``` -------------------------------- ### Managed App Configuration Source: https://context7.com/googlesamples/android-testdpc/llms.txt Pushes a `Bundle` of key/value configuration to a managed application via the Android Managed Configuration (AppRestrictions) framework. ```APIDOC ## setApplicationRestrictions — Managed App Config ### Description Pushes a `Bundle` of key/value configuration to a managed application via the Android Managed Configuration (AppRestrictions) framework. ### Method ```java gateway.setApplicationRestrictions(packageName, config, onSuccess, onError); Bundle getApplicationRestrictions(packageName); Bundle getSelfRestrictions(); ``` ### Parameters #### `setApplicationRestrictions` Parameters - **packageName** (String) - The package name of the target application. - **config** (Bundle) - A `Bundle` containing the key/value restrictions. - **onSuccess** (Consumer) - Callback for successful operation. - **onError** (Consumer) - Callback for operation failure. #### `getApplicationRestrictions` Parameters - **packageName** (String) - The package name of the target application. ### Request Example (Java) ```java Bundle config = new Bundle(); config.putString("server_url", "https://corp.example.com"); config.putString("username", "managed_user"); config.putBoolean("vpn_required", true); config.putInt("session_timeout_minutes", 30); gateway.setApplicationRestrictions( "com.example.corpapp", config, (v) -> Log.i(TAG, "Restrictions applied"), (e) -> Log.e(TAG, "Failed to apply restrictions", e)); // Read back (as DPC) Bundle current = gateway.getApplicationRestrictions("com.example.corpapp"); // Read by the target app itself Bundle self = gateway.getSelfRestrictions(); // uses UserManager ``` ### Request Example (adb shell) ```bash # Set app restrictions adb shell dumpsys activity --user 0 service com.afwsamples.testdpc \ set-app-restrictions com.example.corpapp server_url=https://corp.example.com vpn_required=true # Get app restrictions adb shell dumpsys activity --user 0 service com.afwsamples.testdpc \ get-app-restrictions com.example.corpapp # Output: # 2 app restrictionsDevicePolicyManager for com.example.corpapp # server_url = https://corp.example.com # vpn_required = true ``` ``` -------------------------------- ### Manage Application Restrictions Source: https://context7.com/googlesamples/android-testdpc/llms.txt Pushes a `Bundle` of key/value configuration to a managed application using the Android Managed Configuration framework. This allows for silent configuration of app settings. ```java Bundle config = new Bundle(); config.putString("server_url", "https://corp.example.com"); config.putString("username", "managed_user"); config.putBoolean("vpn_required", true); config.putInt("session_timeout_minutes", 30); gateway.setApplicationRestrictions( "com.example.corpapp", config, (v) -> Log.i(TAG, "Restrictions applied"), (e) -> Log.e(TAG, "Failed to apply restrictions", e)); // Read back (as DPC) Bundle current = gateway.getApplicationRestrictions("com.example.corpapp"); // Read by the target app itself Bundle self = gateway.getSelfRestrictions(); // uses UserManager ``` ```bash adb shell dumpsys activity --user 0 service com.afwsamples.testdpc \ set-app-restrictions com.example.corpapp server_url=https://corp.example.com vpn_required=true adb shell dumpsys activity --user 0 service com.afwsamples.testdpc \ get-app-restrictions com.example.corpapp # Output: # 2 app restrictionsDevicePolicyManager for com.example.corpapp # server_url = https://corp.example.com # vpn_required = true ``` -------------------------------- ### Runtime Permission Management Source: https://context7.com/googlesamples/android-testdpc/llms.txt Grants, denies, or resets runtime permission grant states for managed apps, allowing an admin to silently grant sensitive permissions without user prompts. ```APIDOC ## setPermissionGrantState — Runtime Permission Management ### Description Grants, denies, or resets runtime permission grant states for managed apps, allowing an admin to silently grant sensitive permissions without user prompts. ### Method ```java gateway.setPermissionGrantState(packageName, permission, grantState, onSuccess, onError); boolean canAdminGrantSensorsPermissions(); ``` ### Parameters #### `setPermissionGrantState` Parameters - **packageName** (String) - The package name of the target application. - **permission** (String) - The permission to manage (e.g., `Manifest.permission.ACCESS_FINE_LOCATION`). - **grantState** (int) - The desired grant state: `DevicePolicyManager.PERMISSION_GRANT_STATE_GRANTED`, `DevicePolicyManager.PERMISSION_GRANT_STATE_DENIED`, or `DevicePolicyManager.PERMISSION_GRANT_STATE_DEFAULT`. - **onSuccess** (Consumer) - Callback for successful operation. - **onError** (Consumer) - Callback for operation failure. ### Request Example (Java) ```java // Silently grant location permission to a managed app gateway.setPermissionGrantState( "com.example.corpapp", Manifest.permission.ACCESS_FINE_LOCATION, DevicePolicyManager.PERMISSION_GRANT_STATE_GRANTED, (v) -> Log.i(TAG, "Permission granted"), (e) -> Log.e(TAG, "Failed", e)); // Deny a permission (user cannot grant it) gateway.setPermissionGrantState( "com.example.corpapp", Manifest.permission.READ_CONTACTS, DevicePolicyManager.PERMISSION_GRANT_STATE_DENIED, (v) -> Log.i(TAG, "Permission denied"), (e) -> Log.e(TAG, "Failed", e)); // Check if admin can grant sensor permissions (Android 12+) boolean canGrantSensors = gateway.canAdminGrantSensorsPermissions(); ``` ### Request Example (adb shell) ```bash # Set permission grant state for CAMERA to GRANTED (1) adb shell dumpsys activity --user 0 service com.afwsamples.testdpc \ set-permission-grant-state com.example.corpapp android.permission.CAMERA 1 # 1=GRANTED, 2=DENIED, 0=DEFAULT # Get permission grant state for CAMERA adb shell dumpsys activity --user 0 service com.afwsamples.testdpc \ get-permission-grant-state com.example.corpapp android.permission.CAMERA ``` ``` -------------------------------- ### Mark Profile Owner on Organization-Owned Device via ADB Source: https://github.com/googlesamples/android-testdpc/blob/master/README.md Command to mark the Test DPC app as the Profile Owner on an organization-owned device. This is used for Corporate-Owned, Personally Enabled (COPE) scenarios. ```bash adb shell dpm mark-profile-owner-on-organization-owned-device --user 10 com.afwsamples.testdpc/.DeviceAdminReceiver ``` -------------------------------- ### Set ANDROID_HOME Environment Variable Source: https://github.com/googlesamples/android-testdpc/blob/master/README.md Bazel requires the ANDROID_HOME environment variable to be set to your Android SDK path. Add this to your .bashrc on Linux. ```bash export ANDROID_HOME= ``` -------------------------------- ### lockNow / reboot / wipeData Source: https://context7.com/googlesamples/android-testdpc/llms.txt Immediately locks, reboots, or wipes the managed device. ```APIDOC ## lockNow / reboot / wipeData — Device Control Operations Immediately locks, reboots, or wipes the managed device. ### Java Example ```java // Immediate lock (no flags) gateway.lockNow( (v) -> Log.i(TAG, "Device locked"), (e) -> Log.e(TAG, "Lock failed", e)); // Lock with flag to evict credential-encrypted storage key (DO only, API 26+) gateway.lockNow(DevicePolicyManager.FLAG_EVICT_CREDENTIAL_ENCRYPTION_KEY, (v) -> Log.i(TAG, "Locked + credentials evicted"), (e) -> Log.e(TAG, "Failed", e)); // Reboot (Device Owner, affiliated device only, API 24+) gateway.reboot( (v) -> Log.i(TAG, "Rebooting"), (e) -> Log.e(TAG, "Reboot failed", e)); // Factory reset (preserve FRP = 0, or DevicePolicyManager.WIPE_RESET_PROTECTION_DATA) gateway.wipeData(0, (v) -> Log.i(TAG, "Wiping"), (e) -> Log.e(TAG, "Wipe failed", e)); ``` ### ADB Commands ```bash # Lock device adb shell dumpsys activity --user 0 service com.afwsamples.testdpc lock-now # Reboot device adb shell dumpsys activity --user 0 service com.afwsamples.testdpc reboot # Wipe device adb shell dumpsys activity --user 0 service com.afwsamples.testdpc wipe-data --flags 0 ``` ``` -------------------------------- ### Handle onNetworkLogsAvailable Event Source: https://context7.com/googlesamples/android-testdpc/llms.txt Called when a batch of network logs is ready to be retrieved. The batchToken is used to fetch the logs using retrieveNetworkLogs(). ```java // Network logs batch is ready to retrieve @Override public void onNetworkLogsAvailable(Context context, Intent intent, long batchToken, int networkLogsCount) { // batchToken is passed to retrieveNetworkLogs() CommonReceiverOperations.onNetworkLogsAvailable( context, getComponentName(context), batchToken, networkLogsCount); } ```