Secondary Lockscreen API: improve documentation and rename onSurfaceReady method.
- Documentation clarity and method rename per API review feedback.
- Specifying in documentation and implementation that the implementing service must be exported by the Profile Owner.
Bug: 150866056
Bug: 136085151
Test: atest FrameworksServicesTests:DevicePolicyManagerTest
Test: atest KeyguardUpdateMonitorTest
Test: atest AdminSecondaryLockScreenControllerTest
Change-Id: I58175bd6cf8936f5b1267625ca15b4f9c57f4144
diff --git a/api/current.txt b/api/current.txt
index 0cc4013..2df922c 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -6841,7 +6841,7 @@
ctor public DevicePolicyKeyguardService();
method @Nullable public void dismiss();
method @Nullable public final android.os.IBinder onBind(@Nullable android.content.Intent);
- method @Nullable public android.view.SurfaceControlViewHost.SurfacePackage onSurfaceReady(@Nullable android.os.IBinder);
+ method @Nullable public android.view.SurfaceControlViewHost.SurfacePackage onCreateKeyguardSurface(@NonNull android.os.IBinder);
}
public class DevicePolicyManager {
diff --git a/api/system-current.txt b/api/system-current.txt
index ee5c35f..27cdb1e 100755
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -874,7 +874,7 @@
method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isDeviceProvisioned();
method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isDeviceProvisioningConfigApplied();
method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isManagedKiosk();
- method public boolean isSecondaryLockscreenEnabled(int);
+ method public boolean isSecondaryLockscreenEnabled(@NonNull android.os.UserHandle);
method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isUnattendedManagedKiosk();
method @RequiresPermission("android.permission.NOTIFY_PENDING_SYSTEM_UPDATE") public void notifyPendingSystemUpdate(long);
method @RequiresPermission("android.permission.NOTIFY_PENDING_SYSTEM_UPDATE") public void notifyPendingSystemUpdate(long, boolean);
diff --git a/core/java/android/app/admin/DevicePolicyKeyguardService.java b/core/java/android/app/admin/DevicePolicyKeyguardService.java
index 2ac5ebf..5b7e387 100644
--- a/core/java/android/app/admin/DevicePolicyKeyguardService.java
+++ b/core/java/android/app/admin/DevicePolicyKeyguardService.java
@@ -16,6 +16,7 @@
package android.app.admin;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.Service;
import android.content.Intent;
@@ -27,7 +28,7 @@
/**
* Client interface for providing the SystemUI with secondary lockscreen information.
*
- * <p>An implementation must be provided by the device admin app when
+ * <p>An implementation must be provided by the Profile Owner when
* {@link DevicePolicyManager#setSecondaryLockscreenEnabled} is set to true and the service must be
* declared in the manifest as handling the action
* {@link DevicePolicyManager#ACTION_BIND_SECONDARY_LOCKSCREEN_SERVICE}, otherwise the keyguard
@@ -41,10 +42,11 @@
private final IKeyguardClient mClient = new IKeyguardClient.Stub() {
@Override
- public void onSurfaceReady(@Nullable IBinder hostInputToken, IKeyguardCallback callback) {
+ public void onCreateKeyguardSurface(@Nullable IBinder hostInputToken,
+ IKeyguardCallback callback) {
mCallback = callback;
SurfaceControlViewHost.SurfacePackage surfacePackage =
- DevicePolicyKeyguardService.this.onSurfaceReady(hostInputToken);
+ DevicePolicyKeyguardService.this.onCreateKeyguardSurface(hostInputToken);
if (mCallback != null) {
try {
@@ -63,13 +65,27 @@
}
/**
- * Called by keyguard once the host surface for the secondary lockscreen is ready to display
- * remote content.
+ * Called by keyguard once the host surface for the secondary lockscreen is created and ready to
+ * display remote content.
+ *
+ * <p>Implementations are expected to create a Surface hierarchy with view elements for the
+ * admin's desired secondary lockscreen UI, and optionally, interactive elements
+ * that will allow the user to dismiss the secondary lockscreen, subject to the implementation's
+ * requirements. The view hierarchy is expected to be embedded via the
+ * {@link SurfaceControlViewHost} APIs, and returned as a SurfacePackage via
+ * {@link SurfaceControlViewHost#getSurfacePackage}for the keyguard to reparent into its
+ * prepared SurfaceView.
+ *
+ * @param hostInputToken Token of the SurfaceView which will hosting the embedded hierarchy,
+ * primarily required by {@link SurfaceControlViewHost} for ANR reporting.
+ * It will be provided by the keyguard via
+ * {@link android.view.SurfaceView#getHostToken}.
* @return the {@link SurfaceControlViewHost.SurfacePackage} for the Surface the
* secondary lockscreen content is attached to.
*/
@Nullable
- public SurfaceControlViewHost.SurfacePackage onSurfaceReady(@Nullable IBinder hostInputToken) {
+ public SurfaceControlViewHost.SurfacePackage onCreateKeyguardSurface(
+ @NonNull IBinder hostInputToken) {
return null;
}
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 37f1a65..24c012d 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -8658,11 +8658,11 @@
* @hide
*/
@SystemApi
- public boolean isSecondaryLockscreenEnabled(int userId) {
+ public boolean isSecondaryLockscreenEnabled(@NonNull UserHandle userHandle) {
throwIfParentInstance("isSecondaryLockscreenEnabled");
if (mService != null) {
try {
- return mService.isSecondaryLockscreenEnabled(userId);
+ return mService.isSecondaryLockscreenEnabled(userHandle);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 514677e..fc1eb0a 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -255,7 +255,7 @@
String[] getAccountTypesWithManagementDisabledAsUser(int userId, in boolean parent);
void setSecondaryLockscreenEnabled(in ComponentName who, boolean enabled);
- boolean isSecondaryLockscreenEnabled(int userId);
+ boolean isSecondaryLockscreenEnabled(in UserHandle userHandle);
void setLockTaskPackages(in ComponentName who, in String[] packages);
String[] getLockTaskPackages(in ComponentName who);
diff --git a/core/java/android/app/admin/IKeyguardClient.aidl b/core/java/android/app/admin/IKeyguardClient.aidl
index 4bfd990..9b2f3f4 100644
--- a/core/java/android/app/admin/IKeyguardClient.aidl
+++ b/core/java/android/app/admin/IKeyguardClient.aidl
@@ -23,5 +23,5 @@
* @hide
*/
interface IKeyguardClient {
- oneway void onSurfaceReady(in IBinder hostInputToken, in IKeyguardCallback keyguardCallback);
+ oneway void onCreateKeyguardSurface(in IBinder hostInputToken, in IKeyguardCallback keyguardCallback);
}
diff --git a/packages/SystemUI/src/com/android/keyguard/AdminSecondaryLockScreenController.java b/packages/SystemUI/src/com/android/keyguard/AdminSecondaryLockScreenController.java
index 85724a9..7eb5a8f 100644
--- a/packages/SystemUI/src/com/android/keyguard/AdminSecondaryLockScreenController.java
+++ b/packages/SystemUI/src/com/android/keyguard/AdminSecondaryLockScreenController.java
@@ -170,9 +170,15 @@
private void onSurfaceReady() {
try {
- mClient.onSurfaceReady(mView.getHostToken(), mCallback);
+ IBinder hostToken = mView.getHostToken();
+ // Should never be null when SurfaceView is attached to window.
+ if (hostToken != null) {
+ mClient.onCreateKeyguardSurface(hostToken, mCallback);
+ } else {
+ hide();
+ }
} catch (RemoteException e) {
- Log.e(TAG, "Error in onSurfaceReady", e);
+ Log.e(TAG, "Error in onCreateKeyguardSurface", e);
dismiss(KeyguardUpdateMonitor.getCurrentUser());
}
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 90df124..18357a9 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -962,18 +962,19 @@
private void updateSecondaryLockscreenRequirement(int userId) {
Intent oldIntent = mSecondaryLockscreenRequirement.get(userId);
- boolean enabled = mDevicePolicyManager.isSecondaryLockscreenEnabled(userId);
+ boolean enabled = mDevicePolicyManager.isSecondaryLockscreenEnabled(UserHandle.of(userId));
boolean changed = false;
if (enabled && (oldIntent == null)) {
- ResolveInfo resolveInfo =
- mContext.getPackageManager().resolveService(
- new Intent(
- DevicePolicyManager.ACTION_BIND_SECONDARY_LOCKSCREEN_SERVICE),
- 0);
+ Intent intent = new Intent(
+ DevicePolicyManager.ACTION_BIND_SECONDARY_LOCKSCREEN_SERVICE);
+ ComponentName profileOwnerComponent =
+ mDevicePolicyManager.getProfileOwnerAsUser(userId);
+ intent.setComponent(profileOwnerComponent);
+ ResolveInfo resolveInfo = mContext.getPackageManager().resolveService(intent, 0);
if (resolveInfo != null) {
Intent newIntent = new Intent();
- newIntent.setComponent(resolveInfo.serviceInfo.getComponentName());
+ newIntent.setComponent(profileOwnerComponent);
mSecondaryLockscreenRequirement.put(userId, newIntent);
changed = true;
}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/AdminSecondaryLockScreenControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/AdminSecondaryLockScreenControllerTest.java
index 0e9a245..cf1299f 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/AdminSecondaryLockScreenControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/AdminSecondaryLockScreenControllerTest.java
@@ -105,7 +105,7 @@
IKeyguardCallback callback = (IKeyguardCallback) invocation.getArguments()[1];
callback.onRemoteContentReady(mSurfacePackage);
return null;
- }).when(mKeyguardClient).onSurfaceReady(any(), any(IKeyguardCallback.class));
+ }).when(mKeyguardClient).onCreateKeyguardSurface(any(), any(IKeyguardCallback.class));
mTestController.show(mServiceIntent);
@@ -119,7 +119,7 @@
IKeyguardCallback callback = (IKeyguardCallback) invocation.getArguments()[1];
callback.onDismiss();
return null;
- }).when(mKeyguardClient).onSurfaceReady(any(), any(IKeyguardCallback.class));
+ }).when(mKeyguardClient).onCreateKeyguardSurface(any(), any(IKeyguardCallback.class));
mTestController.show(mServiceIntent);
@@ -133,7 +133,7 @@
IKeyguardCallback callback = (IKeyguardCallback) invocation.getArguments()[1];
callback.onRemoteContentReady(mSurfacePackage);
return null;
- }).when(mKeyguardClient).onSurfaceReady(any(), any(IKeyguardCallback.class));
+ }).when(mKeyguardClient).onCreateKeyguardSurface(any(), any(IKeyguardCallback.class));
mTestController.show(mServiceIntent);
SurfaceView v = verifySurfaceReady();
@@ -151,9 +151,9 @@
}
@Test
- public void testDismissed_onSurfaceReady_RemoteException() throws Exception {
+ public void testDismissed_onCreateKeyguardSurface_RemoteException() throws Exception {
doThrow(new RemoteException()).when(mKeyguardClient)
- .onSurfaceReady(any(), any(IKeyguardCallback.class));
+ .onCreateKeyguardSurface(any(), any(IKeyguardCallback.class));
mTestController.show(mServiceIntent);
@@ -161,9 +161,9 @@
}
@Test
- public void testDismissed_onSurfaceReady_timeout() throws Exception {
- // Mocked KeyguardClient never handles the onSurfaceReady, so the operation times out,
- // resulting in the view being dismissed.
+ public void testDismissed_onCreateKeyguardSurface_timeout() throws Exception {
+ // Mocked KeyguardClient never handles the onCreateKeyguardSurface, so the operation
+ // times out, resulting in the view being dismissed.
doAnswer(answerVoid(Runnable::run)).when(mHandler)
.postDelayed(any(Runnable.class), anyLong());
@@ -178,7 +178,7 @@
verify(mParent).addView(captor.capture());
mTestableLooper.processAllMessages();
- verify(mKeyguardClient).onSurfaceReady(any(), any(IKeyguardCallback.class));
+ verify(mKeyguardClient).onCreateKeyguardSurface(any(), any(IKeyguardCallback.class));
return captor.getValue();
}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
index bd50a73..9d9ba1b 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
@@ -38,6 +38,7 @@
import android.app.admin.DevicePolicyManager;
import android.app.trust.TrustManager;
import android.content.BroadcastReceiver;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
@@ -567,7 +568,10 @@
ResolveInfo resolveInfo = new ResolveInfo();
resolveInfo.serviceInfo = serviceInfo;
when(mPackageManager.resolveService(any(Intent.class), eq(0))).thenReturn(resolveInfo);
- when(mDevicePolicyManager.isSecondaryLockscreenEnabled(eq(user))).thenReturn(true, false);
+ when(mDevicePolicyManager.isSecondaryLockscreenEnabled(eq(UserHandle.of(user))))
+ .thenReturn(true, false);
+ when(mDevicePolicyManager.getProfileOwnerAsUser(user))
+ .thenReturn(new ComponentName(packageName, cls));
// Initially null.
assertThat(mKeyguardUpdateMonitor.getSecondaryLockscreenRequirement(user)).isNull();
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 6ab5303..ef183a2 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -11440,9 +11440,9 @@
}
@Override
- public boolean isSecondaryLockscreenEnabled(int userId) {
+ public boolean isSecondaryLockscreenEnabled(@NonNull UserHandle userHandle) {
synchronized (getLockObject()) {
- return getUserData(userId).mSecondaryLockscreenEnabled;
+ return getUserData(userHandle.getIdentifier()).mSecondaryLockscreenEnabled;
}
}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index 5bf0d03..7c6ac17 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -4267,12 +4267,14 @@
mContext.binder.callingUid = DpmMockContext.CALLER_UID;
// Initial state is disabled.
- assertFalse(dpm.isSecondaryLockscreenEnabled(DpmMockContext.CALLER_USER_HANDLE));
+ assertFalse(dpm.isSecondaryLockscreenEnabled(UserHandle.of(
+ DpmMockContext.CALLER_USER_HANDLE)));
// Profile owner can set enabled state.
setAsProfileOwner(admin1);
dpm.setSecondaryLockscreenEnabled(admin1, true);
- assertTrue(dpm.isSecondaryLockscreenEnabled(DpmMockContext.CALLER_USER_HANDLE));
+ assertTrue(dpm.isSecondaryLockscreenEnabled(UserHandle.of(
+ DpmMockContext.CALLER_USER_HANDLE)));
// Managed profile managed by different package is unaffiliated - cannot set enabled.
final int managedProfileUserId = 15;
@@ -4289,24 +4291,26 @@
mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
// Initial state is disabled.
- assertFalse(dpm.isSecondaryLockscreenEnabled(UserHandle.USER_SYSTEM));
+ assertFalse(dpm.isSecondaryLockscreenEnabled(UserHandle.of(UserHandle.USER_SYSTEM)));
// Device owners can set enabled state.
setupDeviceOwner();
dpm.setSecondaryLockscreenEnabled(admin1, true);
- assertTrue(dpm.isSecondaryLockscreenEnabled(UserHandle.USER_SYSTEM));
+ assertTrue(dpm.isSecondaryLockscreenEnabled(UserHandle.of(UserHandle.USER_SYSTEM)));
}
public void testSecondaryLockscreen_nonOwner() throws Exception {
mContext.binder.callingUid = DpmMockContext.CALLER_UID;
// Initial state is disabled.
- assertFalse(dpm.isSecondaryLockscreenEnabled(DpmMockContext.CALLER_USER_HANDLE));
+ assertFalse(dpm.isSecondaryLockscreenEnabled(UserHandle.of(
+ DpmMockContext.CALLER_USER_HANDLE)));
// Non-DO/PO cannot set enabled state.
assertExpectException(SecurityException.class, /* messageRegex= */ null,
() -> dpm.setSecondaryLockscreenEnabled(admin1, true));
- assertFalse(dpm.isSecondaryLockscreenEnabled(DpmMockContext.CALLER_USER_HANDLE));
+ assertFalse(dpm.isSecondaryLockscreenEnabled(UserHandle.of(
+ DpmMockContext.CALLER_USER_HANDLE)));
}
public void testIsDeviceManaged() throws Exception {