AI-generated Key Takeaways
-
The Android Management API SDK allows an extension app to communicate with Android Device Policy and execute commands, currently supporting only the
ClearAppDatacommand. -
After integration, an extension app can send command requests, query their status, and receive status change notifications.
-
To issue a command, an extension app uses an
IssueCommandRequestcontaining details about the command and its parameters. -
The status of a previously issued command request can be queried using the command ID returned after successfully issuing the command.
-
Extension apps can optionally register a
CommandListenerthrough an extendedNotificationReceiverServiceto receive updates for long-running command status changes. -
Enabling direct communication between the extension app and ADP requires configuring an
extensionConfigpolicy, including the app's signing key fingerprints and the optional notification receiver.
The Android Management API (AMAPI) SDK enables an EMM-specified extension app to
communicate directly with Android Device Policy (ADP) and execute Commands
on the device.
Integrate with the AMAPI SDK provides more information about this library and how to add it to your application.
Once integrated the SDK, your extension app can communicate with ADP to:
Issue Command
An extension app can request for commands to be issued using ADP.
IssueCommandRequest contains the request object that will contain detail on
the command to be issued and specific parameters.
The following snippet shows how to issue a request to clear the package's data:
import android.util.Log;
...
import com.google.android.managementapi.commands.LocalCommandClientFactory;
import com.google.android.managementapi.commands.model.Command;
import com.google.android.managementapi.commands.model.GetCommandRequest;
import com.google.android.managementapi.commands.model.IssueCommandRequest;
import com.google.android.managementapi.commands.model.IssueCommandRequest.ClearAppsData;
import com.google.common.collect.ImmutableList;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.MoreExecutors;
...
void issueClearAppDataCommand(ImmutableList<String> packageNames) {
Futures.addCallback(
LocalCommandClientFactory.create(getContext())
.issueCommand(createClearAppRequest(packageNames)),
new FutureCallback<Command>() {
@Override
public void onSuccess(Command result) {
// Process the returned command result here
Log.i(TAG, "Successfully issued command");
}
@Override
public void onFailure(Throwable t) {
Log.e(TAG, "Failed to issue command", t);
}
},
MoreExecutors.directExecutor());
}
IssueCommandRequest createClearAppRequest(ImmutableList<String> packageNames) {
return IssueCommandRequest.builder()
.setClearAppsData(
ClearAppsData.builder()
.setPackageNames(packageNames)
.build()
)
.build();
}
...
The earlier example shows issuing a clear app data request for specified
packages and waiting until the command has been successfully issued. If
successfully issued, a Command object will be returned with the current
command status and the command ID which can later be used to query the status of
any long running commands.
Get Command
An extension app can query the status of previously issued command requests. To
retrieve a command's status, you will need the command ID (available from the
issue command request). The following snippet shows how to send a
GetCommandRequest to ADP.
import android.util.Log;
...
import com.google.android.managementapi.commands.LocalCommandClientFactory;
...
import com.google.android.managementapi.commands.model.GetCommandRequest;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.MoreExecutors;
...
void getCommand(String commandId) {
Futures.addCallback(
LocalCommandClientFactory.create(getApplication())
.getCommand(GetCommandRequest.builder().setCommandId(commandId).build()),
new FutureCallback<Command>() {
@Override
public void onSuccess(Command result) {
// Process the returned command result here
Log.i(Constants.TAG, "Successfully issued command");
}
@Override
public void onFailure(Throwable t) {
Log.e(Constants.TAG, "Failed to issue command", t);
}
},
MoreExecutors.directExecutor());
}
...
Listen to Command status change callbacks
An extension app can optionally register a callback to receive updates for status changes of long running commands following these steps:
- Command status changes are notified to
CommandListener, implement this interface in your app and provide implementation on how to handle the received status updates. - Extend
NotificationReceiverServiceand provide aCommandListenerinstance through thegetCommandListenermethod. Specify class name of extended
NotificationReceiverServicein the Android Management API policy (see Policy Configuration).import com.google.android.managementapi.commands.CommandListener; import com.google.android.managementapi.notification.NotificationReceiverService; ... public class SampleCommandService extends NotificationReceiverService { @Override public CommandListener getCommandListener() { // return the concrete implementation from previous step return ...; } }
Policy Configuration
To enable the extension app to communicate directly with ADP, the EMM has to
provide an extensionConfig policy.
"applications": [{
"packageName": "com.amapi.extensibility.demo",
...
"extensionConfig": {
"signingKeyFingerprintsSha256": [
// Include signing key of extension app
],
// Optional if callback is implemented
"notificationReceiver": "com.amapi.extensibility.demo.notification.SampleCommandService"
}
}]
Testing
Unit testing
LocalCommandClient is an interface and thus allows to provide a testable
implementation.
Integration testing
The following information will be needed to test with ADP:
- Package name of the extension app.
- The hex-encoded SHA-256 hash of the Signature associated with the app package.
- Optionally, if testing callback - fully qualified name of the service from
the newly introduced service to support callback. (Fully qualified name of
CommandServicein the example).