Copyright (C) 2014 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.
/** * Copyright (C) 2014 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.service.trust; import android.Manifest; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.SdkConstant; import android.annotation.SystemApi; import android.app.Service; import android.app.admin.DevicePolicyManager; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.ServiceInfo; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.Message; import android.os.PersistableBundle; import android.os.RemoteException; import android.os.UserHandle; import android.os.UserManager; import android.util.Log; import android.util.Slog; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.List;
A service that notifies the system about whether it believes the environment of the device to be trusted.

Trust agents may only be provided by the platform. It is expected that there is only one trust agent installed on the platform. In the event there is more than one, either trust agent can enable trust.

To extend this class, you must declare the service in your manifest file with the BIND_TRUST_AGENT.BIND_TRUST_AGENT permission and include an intent filter with the SERVICE_INTERFACE action. For example:

<service android:name=".TrustAgent"
         android:label="@string/service_name"
         android:permission="android.permission.BIND_TRUST_AGENT">
    <intent-filter>
        <action android:name="android.service.trust.TrustAgentService" />
    </intent-filter>
    <meta-data android:name="android.service.trust.trustagent"
         android:value="@xml/trust_agent" />
</service>

The associated meta-data file can specify an activity that is accessible through Settings and should allow configuring the trust agent, as defined in TrustAgent.TrustAgent. For example:

<trust-agent xmlns:android="http://schemas.android.com/apk/res/android"
         android:settingsActivity=".TrustAgentSettings" />
@hide
/** * A service that notifies the system about whether it believes the environment of the device * to be trusted. * * <p>Trust agents may only be provided by the platform. It is expected that there is only * one trust agent installed on the platform. In the event there is more than one, * either trust agent can enable trust. * </p> * * <p>To extend this class, you must declare the service in your manifest file with * the {@link android.Manifest.permission#BIND_TRUST_AGENT} permission * and include an intent filter with the {@link #SERVICE_INTERFACE} action. For example:</p> * <pre> * &lt;service android:name=".TrustAgent" * android:label="&#64;string/service_name" * android:permission="android.permission.BIND_TRUST_AGENT"> * &lt;intent-filter> * &lt;action android:name="android.service.trust.TrustAgentService" /> * &lt;/intent-filter> * &lt;meta-data android:name="android.service.trust.trustagent" * android:value="&#64;xml/trust_agent" /> * &lt;/service></pre> * * <p>The associated meta-data file can specify an activity that is accessible through Settings * and should allow configuring the trust agent, as defined in * {@link android.R.styleable#TrustAgent}. For example:</p> * * <pre> * &lt;trust-agent xmlns:android="http://schemas.android.com/apk/res/android" * android:settingsActivity=".TrustAgentSettings" /></pre> * * @hide */
@SystemApi public class TrustAgentService extends Service { private final String TAG = TrustAgentService.class.getSimpleName() + "[" + getClass().getSimpleName() + "]"; private static final boolean DEBUG = false;
The Intent that must be declared as handled by the service.
/** * The {@link Intent} that must be declared as handled by the service. */
@SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION) public static final String SERVICE_INTERFACE = "android.service.trust.TrustAgentService";
The name of the meta-data tag pointing to additional configuration of the trust agent.
/** * The name of the {@code meta-data} tag pointing to additional configuration of the trust * agent. */
public static final String TRUST_AGENT_META_DATA = "android.service.trust.trustagent";
Flag for grantTrust(CharSequence, long, int) indicating that trust is being granted as the direct result of user action - such as solving a security challenge. The hint is used by the system to optimize the experience. Behavior may vary by device and release, so one should only set this parameter if it meets the above criteria rather than relying on the behavior of any particular device or release.
/** * Flag for {@link #grantTrust(CharSequence, long, int)} indicating that trust is being granted * as the direct result of user action - such as solving a security challenge. The hint is used * by the system to optimize the experience. Behavior may vary by device and release, so * one should only set this parameter if it meets the above criteria rather than relying on * the behavior of any particular device or release. */
public static final int FLAG_GRANT_TRUST_INITIATED_BY_USER = 1 << 0;
Flag for grantTrust(CharSequence, long, int) indicating that the agent would like to dismiss the keyguard. When using this flag, the TrustAgentService must ensure it is only set in response to a direct user action with the expectation of dismissing the keyguard.
/** * Flag for {@link #grantTrust(CharSequence, long, int)} indicating that the agent would like * to dismiss the keyguard. When using this flag, the {@code TrustAgentService} must ensure * it is only set in response to a direct user action with the expectation of dismissing the * keyguard. */
public static final int FLAG_GRANT_TRUST_DISMISS_KEYGUARD = 1 << 1;
@hide
/** @hide */
@Retention(RetentionPolicy.SOURCE) @IntDef(flag = true, prefix = { "FLAG_GRANT_TRUST_" }, value = { FLAG_GRANT_TRUST_INITIATED_BY_USER, FLAG_GRANT_TRUST_DISMISS_KEYGUARD, }) public @interface GrantTrustFlags {}
Int enum indicating that escrow token is active. See onEscrowTokenStateReceived(long, int)
/** * Int enum indicating that escrow token is active. * See {@link #onEscrowTokenStateReceived(long, int)} * */
public static final int TOKEN_STATE_ACTIVE = 1;
Int enum indicating that escow token is inactive. See onEscrowTokenStateReceived(long, int)
/** * Int enum indicating that escow token is inactive. * See {@link #onEscrowTokenStateReceived(long, int)} * */
public static final int TOKEN_STATE_INACTIVE = 0;
@hide
/** @hide */
@Retention(RetentionPolicy.SOURCE) @IntDef(flag = true, prefix = { "TOKEN_STATE_" }, value = { TOKEN_STATE_ACTIVE, TOKEN_STATE_INACTIVE, }) public @interface TokenState {} private static final int MSG_UNLOCK_ATTEMPT = 1; private static final int MSG_CONFIGURE = 2; private static final int MSG_TRUST_TIMEOUT = 3; private static final int MSG_DEVICE_LOCKED = 4; private static final int MSG_DEVICE_UNLOCKED = 5; private static final int MSG_UNLOCK_LOCKOUT = 6; private static final int MSG_ESCROW_TOKEN_ADDED = 7; private static final int MSG_ESCROW_TOKEN_STATE_RECEIVED = 8; private static final int MSG_ESCROW_TOKEN_REMOVED = 9; private static final String EXTRA_TOKEN = "token"; private static final String EXTRA_TOKEN_HANDLE = "token_handle"; private static final String EXTRA_USER_HANDLE = "user_handle"; private static final String EXTRA_TOKEN_STATE = "token_state"; private static final String EXTRA_TOKEN_REMOVED_RESULT = "token_removed_result";
Class containing raw data for a given configuration request.
/** * Class containing raw data for a given configuration request. */
private static final class ConfigurationData { final IBinder token; final List<PersistableBundle> options; ConfigurationData(List<PersistableBundle> opts, IBinder t) { options = opts; token = t; } } private ITrustAgentServiceCallback mCallback; private Runnable mPendingGrantTrustTask; private boolean mManagingTrust; // Lock used to access mPendingGrantTrustTask and mCallback. private final Object mLock = new Object(); private Handler mHandler = new Handler() { public void handleMessage(android.os.Message msg) { switch (msg.what) { case MSG_UNLOCK_ATTEMPT: onUnlockAttempt(msg.arg1 != 0); break; case MSG_UNLOCK_LOCKOUT: onDeviceUnlockLockout(msg.arg1); break; case MSG_CONFIGURE: { ConfigurationData data = (ConfigurationData) msg.obj; boolean result = onConfigure(data.options); if (data.token != null) { try { synchronized (mLock) { mCallback.onConfigureCompleted(result, data.token); } } catch (RemoteException e) { onError("calling onSetTrustAgentFeaturesEnabledCompleted()"); } } break; } case MSG_TRUST_TIMEOUT: onTrustTimeout(); break; case MSG_DEVICE_LOCKED: onDeviceLocked(); break; case MSG_DEVICE_UNLOCKED: onDeviceUnlocked(); break; case MSG_ESCROW_TOKEN_ADDED: { Bundle data = msg.getData(); byte[] token = data.getByteArray(EXTRA_TOKEN); long handle = data.getLong(EXTRA_TOKEN_HANDLE); UserHandle user = (UserHandle) data.getParcelable(EXTRA_USER_HANDLE); onEscrowTokenAdded(token, handle, user); break; } case MSG_ESCROW_TOKEN_STATE_RECEIVED: { Bundle data = msg.getData(); long handle = data.getLong(EXTRA_TOKEN_HANDLE); int tokenState = data.getInt(EXTRA_TOKEN_STATE, TOKEN_STATE_INACTIVE); onEscrowTokenStateReceived(handle, tokenState); break; } case MSG_ESCROW_TOKEN_REMOVED: { Bundle data = msg.getData(); long handle = data.getLong(EXTRA_TOKEN_HANDLE); boolean success = data.getBoolean(EXTRA_TOKEN_REMOVED_RESULT); onEscrowTokenRemoved(handle, success); break; } } } }; @Override public void onCreate() { super.onCreate(); ComponentName component = new ComponentName(this, getClass()); try { ServiceInfo serviceInfo = getPackageManager().getServiceInfo(component, 0 /* flags */); if (!Manifest.permission.BIND_TRUST_AGENT.equals(serviceInfo.permission)) { throw new IllegalStateException(component.flattenToShortString() + " is not declared with the permission " + "\"" + Manifest.permission.BIND_TRUST_AGENT + "\""); } } catch (PackageManager.NameNotFoundException e) { Log.e(TAG, "Can't get ServiceInfo for " + component.toShortString()); } }
Called after the user attempts to authenticate in keyguard with their device credentials, such as pin, pattern or password.
Params:
  • successful – true if the user successfully completed the challenge.
/** * Called after the user attempts to authenticate in keyguard with their device credentials, * such as pin, pattern or password. * * @param successful true if the user successfully completed the challenge. */
public void onUnlockAttempt(boolean successful) { }
Called when the timeout provided by the agent expires. Note that this may be called earlier than requested by the agent if the trust timeout is adjusted by the system or DevicePolicyManager. The agent is expected to re-evaluate the trust state and only call grantTrust(CharSequence, long, boolean) if the trust state should be continued.
/** * Called when the timeout provided by the agent expires. Note that this may be called earlier * than requested by the agent if the trust timeout is adjusted by the system or * {@link DevicePolicyManager}. The agent is expected to re-evaluate the trust state and only * call {@link #grantTrust(CharSequence, long, boolean)} if the trust state should be * continued. */
public void onTrustTimeout() { }
Called when the device enters a state where a PIN, pattern or password must be entered to unlock it.
/** * Called when the device enters a state where a PIN, pattern or * password must be entered to unlock it. */
public void onDeviceLocked() { }
Called when the device leaves a state where a PIN, pattern or password must be entered to unlock it.
/** * Called when the device leaves a state where a PIN, pattern or * password must be entered to unlock it. */
public void onDeviceUnlocked() { }
Called when the device enters a temporary unlock lockout.

This occurs when the user has consecutively failed to unlock the device too many times, and must wait until a timeout has passed to perform another attempt. The user may then only use strong authentication mechanisms (PIN, pattern or password) to unlock the device. Calls to grantTrust(CharSequence, long, int) will be ignored until the user has unlocked the device and onDeviceUnlocked() is called.

Params:
  • timeoutMs – The amount of time, in milliseconds, that needs to elapse before the user can attempt to unlock the device again.
/** * Called when the device enters a temporary unlock lockout. * * <p>This occurs when the user has consecutively failed to unlock the device too many times, * and must wait until a timeout has passed to perform another attempt. The user may then only * use strong authentication mechanisms (PIN, pattern or password) to unlock the device. * Calls to {@link #grantTrust(CharSequence, long, int)} will be ignored until the user has * unlocked the device and {@link #onDeviceUnlocked()} is called. * * @param timeoutMs The amount of time, in milliseconds, that needs to elapse before the user * can attempt to unlock the device again. */
public void onDeviceUnlockLockout(long timeoutMs) { }
Called when an escrow token is added for user userId.
Params:
  • token – the added token
  • handle – the handle to the corresponding internal synthetic password. A user is unlocked by presenting both handle and escrow token.
  • user – the user to which the escrow token is added.
/** * Called when an escrow token is added for user userId. * * @param token the added token * @param handle the handle to the corresponding internal synthetic password. A user is unlocked * by presenting both handle and escrow token. * @param user the user to which the escrow token is added. * */
public void onEscrowTokenAdded(byte[] token, long handle, UserHandle user) { }
Called when an escrow token state is received upon request.
Params:
  • handle – the handle to the internal synthetic password.
  • state – the state of the requested escrow token, see TokenState.
/** * Called when an escrow token state is received upon request. * * @param handle the handle to the internal synthetic password. * @param state the state of the requested escrow token, see {@link TokenState}. * */
public void onEscrowTokenStateReceived(long handle, @TokenState int tokenState) { }
Called when an escrow token is removed.
Params:
  • handle – the handle to the removed the synthetic password.
  • successful – whether the removing operaiton is achieved.
/** * Called when an escrow token is removed. * * @param handle the handle to the removed the synthetic password. * @param successful whether the removing operaiton is achieved. * */
public void onEscrowTokenRemoved(long handle, boolean successful) { } private void onError(String msg) { Slog.v(TAG, "Remote exception while " + msg); }
Called when device policy admin wants to enable specific options for agent in response to DevicePolicyManager.setKeyguardDisabledFeatures(ComponentName, int) and DevicePolicyManager.setTrustAgentConfiguration(ComponentName, ComponentName, PersistableBundle).

Agents that support configuration options should overload this method and return 'true'.

Params:
  • options – The aggregated list of options or an empty list if no restrictions apply.
Returns:true if it supports configuration options.
/** * Called when device policy admin wants to enable specific options for agent in response to * {@link DevicePolicyManager#setKeyguardDisabledFeatures(ComponentName, int)} and * {@link DevicePolicyManager#setTrustAgentConfiguration(ComponentName, ComponentName, * PersistableBundle)}. * <p>Agents that support configuration options should overload this method and return 'true'. * * @param options The aggregated list of options or an empty list if no restrictions apply. * @return true if it supports configuration options. */
public boolean onConfigure(List<PersistableBundle> options) { return false; }
Call to grant trust on the device.
Params:
  • message – describes why the device is trusted, e.g. "Trusted by location".
  • durationMs – amount of time in milliseconds to keep the device in a trusted state. Trust for this agent will automatically be revoked when the timeout expires unless extended by a subsequent call to this function. The timeout is measured from the invocation of this function as dictated by SystemClock#elapsedRealtime()). For security reasons, the value should be no larger than necessary. The value may be adjusted by the system as necessary to comply with a policy controlled by the system or DevicePolicyManager restrictions. See onTrustTimeout() for determining when trust expires.
  • initiatedByUser – this is a hint to the system that trust is being granted as the direct result of user action - such as solving a security challenge. The hint is used by the system to optimize the experience. Behavior may vary by device and release, so one should only set this parameter if it meets the above criteria rather than relying on the behavior of any particular device or release. Corresponds to FLAG_GRANT_TRUST_INITIATED_BY_USER.
Throws:
Deprecated:use grantTrust(CharSequence, long, int) instead.
/** * Call to grant trust on the device. * * @param message describes why the device is trusted, e.g. "Trusted by location". * @param durationMs amount of time in milliseconds to keep the device in a trusted state. * Trust for this agent will automatically be revoked when the timeout expires unless * extended by a subsequent call to this function. The timeout is measured from the * invocation of this function as dictated by {@link SystemClock#elapsedRealtime())}. * For security reasons, the value should be no larger than necessary. * The value may be adjusted by the system as necessary to comply with a policy controlled * by the system or {@link DevicePolicyManager} restrictions. See {@link #onTrustTimeout()} * for determining when trust expires. * @param initiatedByUser this is a hint to the system that trust is being granted as the * direct result of user action - such as solving a security challenge. The hint is used * by the system to optimize the experience. Behavior may vary by device and release, so * one should only set this parameter if it meets the above criteria rather than relying on * the behavior of any particular device or release. Corresponds to * {@link #FLAG_GRANT_TRUST_INITIATED_BY_USER}. * @throws IllegalStateException if the agent is not currently managing trust. * * @deprecated use {@link #grantTrust(CharSequence, long, int)} instead. */
@Deprecated public final void grantTrust( final CharSequence message, final long durationMs, final boolean initiatedByUser) { grantTrust(message, durationMs, initiatedByUser ? FLAG_GRANT_TRUST_INITIATED_BY_USER : 0); }
Call to grant trust on the device.
Params:
  • message – describes why the device is trusted, e.g. "Trusted by location".
  • durationMs – amount of time in milliseconds to keep the device in a trusted state. Trust for this agent will automatically be revoked when the timeout expires unless extended by a subsequent call to this function. The timeout is measured from the invocation of this function as dictated by SystemClock#elapsedRealtime()). For security reasons, the value should be no larger than necessary. The value may be adjusted by the system as necessary to comply with a policy controlled by the system or DevicePolicyManager restrictions. See onTrustTimeout() for determining when trust expires.
  • flags – TBDocumented
Throws:
/** * Call to grant trust on the device. * * @param message describes why the device is trusted, e.g. "Trusted by location". * @param durationMs amount of time in milliseconds to keep the device in a trusted state. * Trust for this agent will automatically be revoked when the timeout expires unless * extended by a subsequent call to this function. The timeout is measured from the * invocation of this function as dictated by {@link SystemClock#elapsedRealtime())}. * For security reasons, the value should be no larger than necessary. * The value may be adjusted by the system as necessary to comply with a policy controlled * by the system or {@link DevicePolicyManager} restrictions. See {@link #onTrustTimeout()} * for determining when trust expires. * @param flags TBDocumented * @throws IllegalStateException if the agent is not currently managing trust. */
public final void grantTrust( final CharSequence message, final long durationMs, @GrantTrustFlags final int flags) { synchronized (mLock) { if (!mManagingTrust) { throw new IllegalStateException("Cannot grant trust if agent is not managing trust." + " Call setManagingTrust(true) first."); } if (mCallback != null) { try { mCallback.grantTrust(message.toString(), durationMs, flags); } catch (RemoteException e) { onError("calling enableTrust()"); } } else { // Remember trust has been granted so we can effectively grant it once the service // is bound. mPendingGrantTrustTask = new Runnable() { @Override public void run() { grantTrust(message, durationMs, flags); } }; } } }
Call to revoke trust on the device.
/** * Call to revoke trust on the device. */
public final void revokeTrust() { synchronized (mLock) { if (mPendingGrantTrustTask != null) { mPendingGrantTrustTask = null; } if (mCallback != null) { try { mCallback.revokeTrust(); } catch (RemoteException e) { onError("calling revokeTrust()"); } } } }
Call to notify the system if the agent is ready to manage trust. This property is not persistent across recreating the service and defaults to false. Therefore this method is typically called when initializing the agent in onCreate.
Params:
  • managingTrust – indicates if the agent would like to manage trust.
/** * Call to notify the system if the agent is ready to manage trust. * * This property is not persistent across recreating the service and defaults to false. * Therefore this method is typically called when initializing the agent in {@link #onCreate}. * * @param managingTrust indicates if the agent would like to manage trust. */
public final void setManagingTrust(boolean managingTrust) { synchronized (mLock) { if (mManagingTrust != managingTrust) { mManagingTrust = managingTrust; if (mCallback != null) { try { mCallback.setManagingTrust(managingTrust); } catch (RemoteException e) { onError("calling setManagingTrust()"); } } } } }
Call to add an escrow token to derive a synthetic password. A synthetic password is an alternaive to the user-set password/pin/pattern in order to unlock encrypted disk. An escrow token can be taken and internally derive the synthetic password. The new added token will not be acivated until the user input the correct PIN/Passcode/Password once. Result will be return by callback onEscrowTokenAdded(byte[], long)
Params:
  • token – an escrow token of high entropy.
  • user – the user which the escrow token will be added to.
/** * Call to add an escrow token to derive a synthetic password. A synthetic password is an * alternaive to the user-set password/pin/pattern in order to unlock encrypted disk. An escrow * token can be taken and internally derive the synthetic password. The new added token will not * be acivated until the user input the correct PIN/Passcode/Password once. * * Result will be return by callback {@link #onEscrowTokenAdded(long, int)} * * @param token an escrow token of high entropy. * @param user the user which the escrow token will be added to. * */
public final void addEscrowToken(byte[] token, UserHandle user) { synchronized (mLock) { if (mCallback == null) { Slog.w(TAG, "Cannot add escrow token if the agent is not connecting to framework"); throw new IllegalStateException("Trust agent is not connected"); } try { mCallback.addEscrowToken(token, user.getIdentifier()); } catch (RemoteException e) { onError("calling addEscrowToken"); } } }
Call to check the active state of an escrow token. Result will be return in callback onEscrowTokenStateReceived(long, int)
Params:
  • handle – the handle of escrow token to the internal synthetic password.
  • user – the user which the escrow token is added to.
/** * Call to check the active state of an escrow token. * * Result will be return in callback {@link #onEscrowTokenStateReceived(long, boolean)} * * @param handle the handle of escrow token to the internal synthetic password. * @param user the user which the escrow token is added to. * */
public final void isEscrowTokenActive(long handle, UserHandle user) { synchronized (mLock) { if (mCallback == null) { Slog.w(TAG, "Cannot add escrow token if the agent is not connecting to framework"); throw new IllegalStateException("Trust agent is not connected"); } try { mCallback.isEscrowTokenActive(handle, user.getIdentifier()); } catch (RemoteException e) { onError("calling isEscrowTokenActive"); } } }
Call to remove the escrow token. Result will be return in callback onEscrowTokenRemoved(long, boolean)
Params:
  • handle – the handle of escrow tokent to the internal synthetic password.
  • user – the user id which the escrow token is added to.
/** * Call to remove the escrow token. * * Result will be return in callback {@link #onEscrowTokenRemoved(long, boolean)} * * @param handle the handle of escrow tokent to the internal synthetic password. * @param user the user id which the escrow token is added to. * */
public final void removeEscrowToken(long handle, UserHandle user) { synchronized (mLock) { if (mCallback == null) { Slog.w(TAG, "Cannot add escrow token if the agent is not connecting to framework"); throw new IllegalStateException("Trust agent is not connected"); } try { mCallback.removeEscrowToken(handle, user.getIdentifier()); } catch (RemoteException e) { onError("callling removeEscrowToken"); } } }
Call to unlock user's FBE.
Params:
  • handle – the handle of escrow tokent to the internal synthetic password.
  • token – the escrow token
  • user – the user about to be unlocked.
/** * Call to unlock user's FBE. * * @param handle the handle of escrow tokent to the internal synthetic password. * @param token the escrow token * @param user the user about to be unlocked. * */
public final void unlockUserWithToken(long handle, byte[] token, UserHandle user) { UserManager um = (UserManager) getSystemService(Context.USER_SERVICE); if (um.isUserUnlocked(user)) { Slog.i(TAG, "User already unlocked"); return; } synchronized (mLock) { if (mCallback == null) { Slog.w(TAG, "Cannot add escrow token if the agent is not connecting to framework"); throw new IllegalStateException("Trust agent is not connected"); } try { mCallback.unlockUserWithToken(handle, token, user.getIdentifier()); } catch (RemoteException e) { onError("calling unlockUserWithToken"); } } }
Request showing a transient error message on the keyguard. The message will be visible on the lock screen or always on display if possible but can be overridden by other keyguard events of higher priority - eg. fingerprint auth error. Other trust agents may override your message if posted simultaneously.
Params:
  • message – Message to show.
/** * Request showing a transient error message on the keyguard. * The message will be visible on the lock screen or always on display if possible but can be * overridden by other keyguard events of higher priority - eg. fingerprint auth error. * Other trust agents may override your message if posted simultaneously. * * @param message Message to show. */
public final void showKeyguardErrorMessage(@NonNull CharSequence message) { if (message == null) { throw new IllegalArgumentException("message cannot be null"); } synchronized (mLock) { if (mCallback == null) { Slog.w(TAG, "Cannot show message because service is not connected to framework."); throw new IllegalStateException("Trust agent is not connected"); } try { mCallback.showKeyguardErrorMessage(message); } catch (RemoteException e) { onError("calling showKeyguardErrorMessage"); } } } @Override public final IBinder onBind(Intent intent) { if (DEBUG) Slog.v(TAG, "onBind() intent = " + intent); return new TrustAgentServiceWrapper(); } private final class TrustAgentServiceWrapper extends ITrustAgentService.Stub { @Override /* Binder API */ public void onUnlockAttempt(boolean successful) { mHandler.obtainMessage(MSG_UNLOCK_ATTEMPT, successful ? 1 : 0, 0).sendToTarget(); } @Override public void onUnlockLockout(int timeoutMs) { mHandler.obtainMessage(MSG_UNLOCK_LOCKOUT, timeoutMs, 0).sendToTarget(); } @Override /* Binder API */ public void onTrustTimeout() { mHandler.sendEmptyMessage(MSG_TRUST_TIMEOUT); } @Override /* Binder API */ public void onConfigure(List<PersistableBundle> args, IBinder token) { mHandler.obtainMessage(MSG_CONFIGURE, new ConfigurationData(args, token)) .sendToTarget(); } @Override public void onDeviceLocked() throws RemoteException { mHandler.obtainMessage(MSG_DEVICE_LOCKED).sendToTarget(); } @Override public void onDeviceUnlocked() throws RemoteException { mHandler.obtainMessage(MSG_DEVICE_UNLOCKED).sendToTarget(); } @Override /* Binder API */ public void setCallback(ITrustAgentServiceCallback callback) { synchronized (mLock) { mCallback = callback; // The managingTrust property is false implicitly on the server-side, so we only // need to set it here if the agent has decided to manage trust. if (mManagingTrust) { try { mCallback.setManagingTrust(mManagingTrust); } catch (RemoteException e ) { onError("calling setManagingTrust()"); } } if (mPendingGrantTrustTask != null) { mPendingGrantTrustTask.run(); mPendingGrantTrustTask = null; } } } @Override public void onEscrowTokenAdded(byte[] token, long handle, UserHandle user) { Message msg = mHandler.obtainMessage(MSG_ESCROW_TOKEN_ADDED); msg.getData().putByteArray(EXTRA_TOKEN, token); msg.getData().putLong(EXTRA_TOKEN_HANDLE, handle); msg.getData().putParcelable(EXTRA_USER_HANDLE, user); msg.sendToTarget(); } public void onTokenStateReceived(long handle, int tokenState) { Message msg = mHandler.obtainMessage(MSG_ESCROW_TOKEN_STATE_RECEIVED); msg.getData().putLong(EXTRA_TOKEN_HANDLE, handle); msg.getData().putInt(EXTRA_TOKEN_STATE, tokenState); msg.sendToTarget(); } public void onEscrowTokenRemoved(long handle, boolean successful) { Message msg = mHandler.obtainMessage(MSG_ESCROW_TOKEN_REMOVED); msg.getData().putLong(EXTRA_TOKEN_HANDLE, handle); msg.getData().putBoolean(EXTRA_TOKEN_REMOVED_RESULT, successful); msg.sendToTarget(); } } }