diff --git a/core/java/android/app/trust/ITrustListener.aidl b/core/java/android/app/trust/ITrustListener.aidl index 65b024999a5b2..6b9d2c73450ec 100644 --- a/core/java/android/app/trust/ITrustListener.aidl +++ b/core/java/android/app/trust/ITrustListener.aidl @@ -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 trustGrantedMessages); void onTrustManagedChanged(boolean managed, int userId); void onTrustError(in CharSequence message); } \ No newline at end of file diff --git a/core/java/android/app/trust/TrustManager.java b/core/java/android/app/trust/TrustManager.java index 177de835554bf..1b3bed33df89a 100644 --- a/core/java/android/app/trust/TrustManager.java +++ b/core/java/android/app/trust/TrustManager.java @@ -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 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 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 trustGrantedMessages); /** * Reports that whether trust is managed has changed diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java index 5276679ea1041..e281d956c5724 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java @@ -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 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 diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java index a74fd15ab11bc..47e1035fbfef4 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java @@ -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. *

diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java index 7266e41ad7cae..8bb2acf9d011e 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java @@ -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 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(); diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java index 273f8a545db55..4594303436ecb 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java @@ -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 trustGrantedMessages) { mUserHasTrust.put(userId, enabled); } diff --git a/services/core/java/com/android/server/trust/TrustAgentWrapper.java b/services/core/java/com/android/server/trust/TrustAgentWrapper.java index 79231f7097385..efd61c2f99a56 100644 --- a/services/core/java/com/android/server/trust/TrustAgentWrapper.java +++ b/services/core/java/com/android/server/trust/TrustAgentWrapper.java @@ -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); diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java index 4b71742c86c82..038d89017aafb 100644 --- a/services/core/java/com/android/server/trust/TrustManagerService.java +++ b/services/core/java/com/android/server/trust/TrustManagerService.java @@ -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 getTrustGrantedMessages(int userId) { + if (!mStrongAuthTracker.isTrustAllowedForUser(userId)) { + return new ArrayList<>(); + } + + List 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 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);