Trust agents can show a message to the user on grant
When trust has been granted, trust agents can show a message to a user when trust is granted with FLAG_GRANT_TRUST_DISPLAY_MESSAGE. Previously, the message was only used for debugging. Test: atest SystemUITests Fixes: 213911325 Change-Id: Ia449fd98eb0ddac3ea6391c78e76d9e93df8530d
This commit is contained in:
@@ -16,13 +16,16 @@
|
||||
*/
|
||||
package android.app.trust;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Private API to be notified about trust changes.
|
||||
*
|
||||
* {@hide}
|
||||
*/
|
||||
oneway interface ITrustListener {
|
||||
void onTrustChanged(boolean enabled, int userId, int flags);
|
||||
void onTrustChanged(boolean enabled, int userId, int flags,
|
||||
in List<String> trustGrantedMessages);
|
||||
void onTrustManagedChanged(boolean managed, int userId);
|
||||
void onTrustError(in CharSequence message);
|
||||
}
|
||||
@@ -29,6 +29,9 @@ import android.os.Message;
|
||||
import android.os.RemoteException;
|
||||
import android.util.ArrayMap;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* See {@link com.android.server.trust.TrustManagerService}
|
||||
* @hide
|
||||
@@ -43,6 +46,7 @@ public class TrustManager {
|
||||
private static final String TAG = "TrustManager";
|
||||
private static final String DATA_FLAGS = "initiatedByUser";
|
||||
private static final String DATA_MESSAGE = "message";
|
||||
private static final String DATA_GRANTED_MESSAGES = "grantedMessages";
|
||||
|
||||
private final ITrustManager mService;
|
||||
private final ArrayMap<TrustListener, ITrustListener> mTrustListeners;
|
||||
@@ -139,12 +143,15 @@ public class TrustManager {
|
||||
try {
|
||||
ITrustListener.Stub iTrustListener = new ITrustListener.Stub() {
|
||||
@Override
|
||||
public void onTrustChanged(boolean enabled, int userId, int flags) {
|
||||
public void onTrustChanged(boolean enabled, int userId, int flags,
|
||||
List<String> trustGrantedMessages) {
|
||||
Message m = mHandler.obtainMessage(MSG_TRUST_CHANGED, (enabled ? 1 : 0), userId,
|
||||
trustListener);
|
||||
if (flags != 0) {
|
||||
m.getData().putInt(DATA_FLAGS, flags);
|
||||
}
|
||||
m.getData().putCharSequenceArrayList(
|
||||
DATA_GRANTED_MESSAGES, (ArrayList) trustGrantedMessages);
|
||||
m.sendToTarget();
|
||||
}
|
||||
|
||||
@@ -231,14 +238,15 @@ public class TrustManager {
|
||||
switch(msg.what) {
|
||||
case MSG_TRUST_CHANGED:
|
||||
int flags = msg.peekData() != null ? msg.peekData().getInt(DATA_FLAGS) : 0;
|
||||
((TrustListener)msg.obj).onTrustChanged(msg.arg1 != 0, msg.arg2, flags);
|
||||
((TrustListener) msg.obj).onTrustChanged(msg.arg1 != 0, msg.arg2, flags,
|
||||
msg.getData().getStringArrayList(DATA_GRANTED_MESSAGES));
|
||||
break;
|
||||
case MSG_TRUST_MANAGED_CHANGED:
|
||||
((TrustListener)msg.obj).onTrustManagedChanged(msg.arg1 != 0, msg.arg2);
|
||||
break;
|
||||
case MSG_TRUST_ERROR:
|
||||
final CharSequence message = msg.peekData().getCharSequence(DATA_MESSAGE);
|
||||
((TrustListener)msg.obj).onTrustError(message);
|
||||
((TrustListener) msg.obj).onTrustError(message);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -252,8 +260,11 @@ public class TrustManager {
|
||||
* @param flags Flags specified by the trust agent when granting trust. See
|
||||
* {@link android.service.trust.TrustAgentService#grantTrust(CharSequence, long, int)
|
||||
* TrustAgentService.grantTrust(CharSequence, long, int)}.
|
||||
* @param trustGrantedMessages Messages to display to the user when trust has been granted
|
||||
* by one or more trust agents.
|
||||
*/
|
||||
void onTrustChanged(boolean enabled, int userId, int flags);
|
||||
void onTrustChanged(boolean enabled, int userId, int flags,
|
||||
List<String> trustGrantedMessages);
|
||||
|
||||
/**
|
||||
* Reports that whether trust is managed has changed
|
||||
|
||||
@@ -443,7 +443,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTrustChanged(boolean enabled, int userId, int flags) {
|
||||
public void onTrustChanged(boolean enabled, int userId, int flags,
|
||||
List<String> trustGrantedMessages) {
|
||||
Assert.isMainThread();
|
||||
boolean wasTrusted = mUserHasTrust.get(userId, false);
|
||||
mUserHasTrust.put(userId, enabled);
|
||||
@@ -465,6 +466,19 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (KeyguardUpdateMonitor.getCurrentUser() == userId && getUserHasTrust(userId)) {
|
||||
CharSequence message = null;
|
||||
if (trustGrantedMessages != null && trustGrantedMessages.size() > 0) {
|
||||
message = trustGrantedMessages.get(0); // for now only shows the first in the list
|
||||
}
|
||||
for (int i = 0; i < mCallbacks.size(); i++) {
|
||||
KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
|
||||
if (cb != null) {
|
||||
cb.showTrustGrantedMessage(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -23,6 +23,8 @@ import android.os.SystemClock;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.view.WindowManagerPolicyConstants;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.android.settingslib.fuelgauge.BatteryStatus;
|
||||
import com.android.systemui.statusbar.KeyguardIndicationController;
|
||||
|
||||
@@ -215,6 +217,11 @@ public class KeyguardUpdateMonitorCallback {
|
||||
*/
|
||||
public void onTrustGrantedWithFlags(int flags, int userId) { }
|
||||
|
||||
/**
|
||||
* Called when setting the trust granted message.
|
||||
*/
|
||||
public void showTrustGrantedMessage(@Nullable CharSequence message) { }
|
||||
|
||||
/**
|
||||
* Called when a biometric has been acquired.
|
||||
* <p>
|
||||
|
||||
@@ -108,6 +108,7 @@ import org.mockito.MockitoAnnotations;
|
||||
import org.mockito.MockitoSession;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
@@ -178,6 +179,8 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
|
||||
private FeatureFlags mFeatureFlags;
|
||||
@Captor
|
||||
private ArgumentCaptor<StatusBarStateController.StateListener> mStatusBarStateListenerCaptor;
|
||||
@Mock
|
||||
private KeyguardUpdateMonitorCallback mTestCallback;
|
||||
// Direct executor
|
||||
private Executor mBackgroundExecutor = Runnable::run;
|
||||
private Executor mMainExecutor = Runnable::run;
|
||||
@@ -255,11 +258,13 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
|
||||
|
||||
verify(mStatusBarStateController).addCallback(mStatusBarStateListenerCaptor.capture());
|
||||
mStatusBarStateListener = mStatusBarStateListenerCaptor.getValue();
|
||||
mKeyguardUpdateMonitor.registerCallback(mTestCallback);
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
mMockitoSession.finishMocking();
|
||||
mKeyguardUpdateMonitor.removeCallback(mTestCallback);
|
||||
mKeyguardUpdateMonitor.destroy();
|
||||
}
|
||||
|
||||
@@ -599,7 +604,8 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
|
||||
mTestableLooper.processAllMessages();
|
||||
when(mKeyguardBypassController.canBypass()).thenReturn(true);
|
||||
mKeyguardUpdateMonitor.onTrustChanged(true /* enabled */,
|
||||
KeyguardUpdateMonitor.getCurrentUser(), 0 /* flags */);
|
||||
KeyguardUpdateMonitor.getCurrentUser(), 0 /* flags */,
|
||||
new ArrayList<>());
|
||||
mKeyguardUpdateMonitor.onKeyguardVisibilityChanged(true);
|
||||
verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt(), anyBoolean());
|
||||
}
|
||||
@@ -609,7 +615,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
|
||||
mKeyguardUpdateMonitor.dispatchStartedWakingUp();
|
||||
mTestableLooper.processAllMessages();
|
||||
mKeyguardUpdateMonitor.onTrustChanged(true /* enabled */,
|
||||
KeyguardUpdateMonitor.getCurrentUser(), 0 /* flags */);
|
||||
KeyguardUpdateMonitor.getCurrentUser(), 0 /* flags */, new ArrayList<>());
|
||||
mKeyguardUpdateMonitor.onKeyguardVisibilityChanged(true);
|
||||
verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt(),
|
||||
anyBoolean());
|
||||
@@ -754,7 +760,8 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
|
||||
@Test
|
||||
public void testGetUserCanSkipBouncer_whenTrust() {
|
||||
int user = KeyguardUpdateMonitor.getCurrentUser();
|
||||
mKeyguardUpdateMonitor.onTrustChanged(true /* enabled */, user, 0 /* flags */);
|
||||
mKeyguardUpdateMonitor.onTrustChanged(true /* enabled */, user, 0 /* flags */,
|
||||
new ArrayList<>());
|
||||
assertThat(mKeyguardUpdateMonitor.getUserCanSkipBouncer(user)).isTrue();
|
||||
}
|
||||
|
||||
@@ -985,7 +992,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
|
||||
|
||||
// WHEN trust is enabled (ie: via smartlock)
|
||||
mKeyguardUpdateMonitor.onTrustChanged(true /* enabled */,
|
||||
KeyguardUpdateMonitor.getCurrentUser(), 0 /* flags */);
|
||||
KeyguardUpdateMonitor.getCurrentUser(), 0 /* flags */, new ArrayList<>());
|
||||
|
||||
// THEN we shouldn't listen for udfps
|
||||
assertThat(mKeyguardUpdateMonitor.shouldListenForFingerprint(true)).isEqualTo(false);
|
||||
@@ -1069,6 +1076,17 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
|
||||
anyBoolean());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testShowTrustGrantedMessage_onTrustGranted() {
|
||||
// WHEN trust is enabled (ie: via some trust agent) with a trustGranted string
|
||||
mKeyguardUpdateMonitor.onTrustChanged(true /* enabled */,
|
||||
KeyguardUpdateMonitor.getCurrentUser(), 0 /* flags */,
|
||||
Arrays.asList("Unlocked by wearable"));
|
||||
|
||||
// THEN the showTrustGrantedMessage should be called with the first message
|
||||
verify(mTestCallback).showTrustGrantedMessage("Unlocked by wearable");
|
||||
}
|
||||
|
||||
private void setKeyguardBouncerVisibility(boolean isVisible) {
|
||||
mKeyguardUpdateMonitor.sendKeyguardBouncerChanged(isVisible);
|
||||
mTestableLooper.processAllMessages();
|
||||
|
||||
@@ -414,7 +414,8 @@ public class Fingerprint21UdfpsMock extends Fingerprint21 implements TrustManage
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTrustChanged(boolean enabled, int userId, int flags) {
|
||||
public void onTrustChanged(boolean enabled, int userId, int flags,
|
||||
List<String> trustGrantedMessages) {
|
||||
mUserHasTrust.put(userId, enabled);
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package com.android.server.trust;
|
||||
|
||||
import static android.service.trust.TrustAgentService.FLAG_GRANT_TRUST_DISPLAY_MESSAGE;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.app.AlarmManager;
|
||||
import android.app.PendingIntent;
|
||||
@@ -99,6 +101,7 @@ public class TrustAgentWrapper {
|
||||
// Trust state
|
||||
private boolean mTrusted;
|
||||
private CharSequence mMessage;
|
||||
private boolean mDisplayTrustGrantedMessage;
|
||||
private boolean mTrustDisabledByDpm;
|
||||
private boolean mManagingTrust;
|
||||
private IBinder mSetTrustAgentFeaturesToken;
|
||||
@@ -132,6 +135,7 @@ public class TrustAgentWrapper {
|
||||
mTrusted = true;
|
||||
mMessage = (CharSequence) msg.obj;
|
||||
int flags = msg.arg1;
|
||||
mDisplayTrustGrantedMessage = (flags & FLAG_GRANT_TRUST_DISPLAY_MESSAGE) != 0;
|
||||
long durationMs = msg.getData().getLong(DATA_DURATION);
|
||||
if (durationMs > 0) {
|
||||
final long duration;
|
||||
@@ -166,6 +170,7 @@ public class TrustAgentWrapper {
|
||||
// Fall through.
|
||||
case MSG_REVOKE_TRUST:
|
||||
mTrusted = false;
|
||||
mDisplayTrustGrantedMessage = false;
|
||||
mMessage = null;
|
||||
mHandler.removeMessages(MSG_TRUST_TIMEOUT);
|
||||
if (msg.what == MSG_REVOKE_TRUST) {
|
||||
@@ -199,6 +204,7 @@ public class TrustAgentWrapper {
|
||||
mManagingTrust = msg.arg1 != 0;
|
||||
if (!mManagingTrust) {
|
||||
mTrusted = false;
|
||||
mDisplayTrustGrantedMessage = false;
|
||||
mMessage = null;
|
||||
}
|
||||
mTrustManagerService.mArchive.logManagingTrust(mUserId, mName, mManagingTrust);
|
||||
@@ -271,12 +277,13 @@ public class TrustAgentWrapper {
|
||||
private ITrustAgentServiceCallback mCallback = new ITrustAgentServiceCallback.Stub() {
|
||||
|
||||
@Override
|
||||
public void grantTrust(CharSequence userMessage, long durationMs, int flags) {
|
||||
if (DEBUG) Slog.d(TAG, "enableTrust(" + userMessage + ", durationMs = " + durationMs
|
||||
public void grantTrust(CharSequence message, long durationMs, int flags) {
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG, "enableTrust(" + message + ", durationMs = " + durationMs
|
||||
+ ", flags = " + flags + ")");
|
||||
}
|
||||
|
||||
Message msg = mHandler.obtainMessage(
|
||||
MSG_GRANT_TRUST, flags, 0, userMessage);
|
||||
Message msg = mHandler.obtainMessage(MSG_GRANT_TRUST, flags, 0, message);
|
||||
msg.getData().putLong(DATA_DURATION, durationMs);
|
||||
msg.sendToTarget();
|
||||
}
|
||||
@@ -579,6 +586,14 @@ public class TrustAgentWrapper {
|
||||
return mMessage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the trust agent would like to display {@link #getMessage()} to the user when trust
|
||||
* is granted.
|
||||
*/
|
||||
public boolean shouldDisplayTrustGrantedMessage() {
|
||||
return mDisplayTrustGrantedMessage;
|
||||
}
|
||||
|
||||
public void destroy() {
|
||||
mHandler.removeMessages(MSG_RESTART_TIMEOUT);
|
||||
|
||||
|
||||
@@ -74,7 +74,6 @@ import com.android.internal.content.PackageMonitor;
|
||||
import com.android.internal.util.DumpUtils;
|
||||
import com.android.internal.widget.LockPatternUtils;
|
||||
import com.android.server.SystemService;
|
||||
import com.android.server.SystemService.TargetUser;
|
||||
|
||||
import org.xmlpull.v1.XmlPullParser;
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
@@ -388,7 +387,6 @@ public class TrustManagerService extends SystemService {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void updateTrust(int userId, int flags) {
|
||||
updateTrust(userId, flags, false /* isFromUnlock */);
|
||||
}
|
||||
@@ -428,7 +426,7 @@ public class TrustManagerService extends SystemService {
|
||||
changed = mUserIsTrusted.get(userId) != trusted;
|
||||
mUserIsTrusted.put(userId, trusted);
|
||||
}
|
||||
dispatchOnTrustChanged(trusted, userId, flags);
|
||||
dispatchOnTrustChanged(trusted, userId, flags, getTrustGrantedMessages(userId));
|
||||
if (changed) {
|
||||
refreshDeviceLockedForUser(userId);
|
||||
if (!trusted) {
|
||||
@@ -933,6 +931,24 @@ public class TrustManagerService extends SystemService {
|
||||
return false;
|
||||
}
|
||||
|
||||
private List<String> getTrustGrantedMessages(int userId) {
|
||||
if (!mStrongAuthTracker.isTrustAllowedForUser(userId)) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
List<String> trustGrantedMessages = new ArrayList<>();
|
||||
for (int i = 0; i < mActiveAgents.size(); i++) {
|
||||
AgentInfo info = mActiveAgents.valueAt(i);
|
||||
if (info.userId == userId
|
||||
&& info.agent.isTrusted()
|
||||
&& info.agent.shouldDisplayTrustGrantedMessage()
|
||||
&& !TextUtils.isEmpty(info.agent.getMessage())) {
|
||||
trustGrantedMessages.add(info.agent.getMessage().toString());
|
||||
}
|
||||
}
|
||||
return trustGrantedMessages;
|
||||
}
|
||||
|
||||
private boolean aggregateIsTrustManaged(int userId) {
|
||||
if (!mStrongAuthTracker.isTrustAllowedForUser(userId)) {
|
||||
return false;
|
||||
@@ -993,7 +1009,8 @@ public class TrustManagerService extends SystemService {
|
||||
}
|
||||
}
|
||||
|
||||
private void dispatchOnTrustChanged(boolean enabled, int userId, int flags) {
|
||||
private void dispatchOnTrustChanged(boolean enabled, int userId, int flags,
|
||||
@NonNull List<String> trustGrantedMessages) {
|
||||
if (DEBUG) {
|
||||
Log.i(TAG, "onTrustChanged(" + enabled + ", " + userId + ", 0x"
|
||||
+ Integer.toHexString(flags) + ")");
|
||||
@@ -1001,7 +1018,7 @@ public class TrustManagerService extends SystemService {
|
||||
if (!enabled) flags = 0;
|
||||
for (int i = 0; i < mTrustListeners.size(); i++) {
|
||||
try {
|
||||
mTrustListeners.get(i).onTrustChanged(enabled, userId, flags);
|
||||
mTrustListeners.get(i).onTrustChanged(enabled, userId, flags, trustGrantedMessages);
|
||||
} catch (DeadObjectException e) {
|
||||
Slog.d(TAG, "Removing dead TrustListener.");
|
||||
mTrustListeners.remove(i);
|
||||
|
||||
Reference in New Issue
Block a user