Merge "Fix secondary lock screen implementation such that DevicePolicyKeyguardService calls are made on the main (UI) thread." into rvc-dev
This commit is contained in:
@@ -16,12 +16,15 @@
|
|||||||
|
|
||||||
package android.app.admin;
|
package android.app.admin;
|
||||||
|
|
||||||
|
import android.annotation.MainThread;
|
||||||
import android.annotation.NonNull;
|
import android.annotation.NonNull;
|
||||||
import android.annotation.Nullable;
|
import android.annotation.Nullable;
|
||||||
import android.annotation.SystemApi;
|
import android.annotation.SystemApi;
|
||||||
import android.app.Service;
|
import android.app.Service;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.os.Handler;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
|
import android.os.Looper;
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.SurfaceControlViewHost;
|
import android.view.SurfaceControlViewHost;
|
||||||
@@ -41,26 +44,33 @@ import android.view.SurfaceControlViewHost;
|
|||||||
@SystemApi
|
@SystemApi
|
||||||
public class DevicePolicyKeyguardService extends Service {
|
public class DevicePolicyKeyguardService extends Service {
|
||||||
private static final String TAG = "DevicePolicyKeyguardService";
|
private static final String TAG = "DevicePolicyKeyguardService";
|
||||||
|
private final Handler mHandler = new Handler(Looper.getMainLooper());
|
||||||
private IKeyguardCallback mCallback;
|
private IKeyguardCallback mCallback;
|
||||||
|
|
||||||
private final IKeyguardClient mClient = new IKeyguardClient.Stub() {
|
private final IKeyguardClient mClient = new IKeyguardClient.Stub() {
|
||||||
|
@MainThread
|
||||||
@Override
|
@Override
|
||||||
public void onCreateKeyguardSurface(@Nullable IBinder hostInputToken,
|
public void onCreateKeyguardSurface(@Nullable IBinder hostInputToken,
|
||||||
IKeyguardCallback callback) {
|
@NonNull IKeyguardCallback callback) {
|
||||||
mCallback = callback;
|
mCallback = callback;
|
||||||
SurfaceControlViewHost.SurfacePackage surfacePackage =
|
mHandler.post(() -> {
|
||||||
DevicePolicyKeyguardService.this.onCreateKeyguardSurface(hostInputToken);
|
SurfaceControlViewHost.SurfacePackage surfacePackage =
|
||||||
|
DevicePolicyKeyguardService.this.onCreateKeyguardSurface(hostInputToken);
|
||||||
|
|
||||||
if (mCallback != null) {
|
|
||||||
try {
|
try {
|
||||||
mCallback.onRemoteContentReady(surfacePackage);
|
mCallback.onRemoteContentReady(surfacePackage);
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
Log.e(TAG, "Failed to return created SurfacePackage", e);
|
Log.e(TAG, "Failed to return created SurfacePackage", e);
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDestroy() {
|
||||||
|
mHandler.removeCallbacksAndMessages(null);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Nullable
|
@Nullable
|
||||||
public final IBinder onBind(@Nullable Intent intent) {
|
public final IBinder onBind(@Nullable Intent intent) {
|
||||||
@@ -97,6 +107,10 @@ public class DevicePolicyKeyguardService extends Service {
|
|||||||
*/
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
public void dismiss() {
|
public void dismiss() {
|
||||||
|
if (mCallback == null) {
|
||||||
|
Log.w(TAG, "KeyguardCallback was unexpectedly null");
|
||||||
|
return;
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
mCallback.onDismiss();
|
mCallback.onDismiss();
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
|
|||||||
@@ -34,6 +34,8 @@ import android.view.ViewGroup;
|
|||||||
|
|
||||||
import com.android.internal.annotations.VisibleForTesting;
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
|
|
||||||
|
import java.util.NoSuchElementException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Encapsulates all logic for secondary lockscreen state management.
|
* Encapsulates all logic for secondary lockscreen state management.
|
||||||
*/
|
*/
|
||||||
@@ -79,7 +81,9 @@ public class AdminSecondaryLockScreenController {
|
|||||||
private final IKeyguardCallback mCallback = new IKeyguardCallback.Stub() {
|
private final IKeyguardCallback mCallback = new IKeyguardCallback.Stub() {
|
||||||
@Override
|
@Override
|
||||||
public void onDismiss() {
|
public void onDismiss() {
|
||||||
dismiss(UserHandle.getCallingUserId());
|
mHandler.post(() -> {
|
||||||
|
dismiss(UserHandle.getCallingUserId());
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -91,7 +95,9 @@ public class AdminSecondaryLockScreenController {
|
|||||||
if (surfacePackage != null) {
|
if (surfacePackage != null) {
|
||||||
mView.setChildSurfacePackage(surfacePackage);
|
mView.setChildSurfacePackage(surfacePackage);
|
||||||
} else {
|
} else {
|
||||||
dismiss(KeyguardUpdateMonitor.getCurrentUser());
|
mHandler.post(() -> {
|
||||||
|
dismiss(KeyguardUpdateMonitor.getCurrentUser());
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -122,6 +128,7 @@ public class AdminSecondaryLockScreenController {
|
|||||||
// If the remote content is not readied within the timeout period,
|
// If the remote content is not readied within the timeout period,
|
||||||
// move on without the secondary lockscreen.
|
// move on without the secondary lockscreen.
|
||||||
dismiss(userId);
|
dismiss(userId);
|
||||||
|
Log.w(TAG, "Timed out waiting for secondary lockscreen content.");
|
||||||
},
|
},
|
||||||
REMOTE_CONTENT_READY_TIMEOUT_MILLIS);
|
REMOTE_CONTENT_READY_TIMEOUT_MILLIS);
|
||||||
}
|
}
|
||||||
@@ -150,8 +157,12 @@ public class AdminSecondaryLockScreenController {
|
|||||||
* Displays the Admin security Surface view.
|
* Displays the Admin security Surface view.
|
||||||
*/
|
*/
|
||||||
public void show(Intent serviceIntent) {
|
public void show(Intent serviceIntent) {
|
||||||
mContext.bindService(serviceIntent, mConnection, Context.BIND_AUTO_CREATE);
|
if (mClient == null) {
|
||||||
mParent.addView(mView);
|
mContext.bindService(serviceIntent, mConnection, Context.BIND_AUTO_CREATE);
|
||||||
|
}
|
||||||
|
if (!mView.isAttachedToWindow()) {
|
||||||
|
mParent.addView(mView);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -162,7 +173,11 @@ public class AdminSecondaryLockScreenController {
|
|||||||
mParent.removeView(mView);
|
mParent.removeView(mView);
|
||||||
}
|
}
|
||||||
if (mClient != null) {
|
if (mClient != null) {
|
||||||
mClient.asBinder().unlinkToDeath(mKeyguardClientDeathRecipient, 0);
|
try {
|
||||||
|
mClient.asBinder().unlinkToDeath(mKeyguardClientDeathRecipient, 0);
|
||||||
|
} catch (NoSuchElementException e) {
|
||||||
|
Log.w(TAG, "IKeyguardClient death recipient already released");
|
||||||
|
}
|
||||||
mContext.unbindService(mConnection);
|
mContext.unbindService(mConnection);
|
||||||
mClient = null;
|
mClient = null;
|
||||||
}
|
}
|
||||||
@@ -185,10 +200,12 @@ public class AdminSecondaryLockScreenController {
|
|||||||
|
|
||||||
private void dismiss(int userId) {
|
private void dismiss(int userId) {
|
||||||
mHandler.removeCallbacksAndMessages(null);
|
mHandler.removeCallbacksAndMessages(null);
|
||||||
if (mView != null && mView.isAttachedToWindow()
|
if (mView.isAttachedToWindow() && userId == KeyguardUpdateMonitor.getCurrentUser()) {
|
||||||
&& userId == KeyguardUpdateMonitor.getCurrentUser()) {
|
|
||||||
hide();
|
hide();
|
||||||
mKeyguardCallback.dismiss(true, userId);
|
if (mKeyguardCallback != null) {
|
||||||
|
mKeyguardCallback.dismiss(/* securityVerified= */ true, userId,
|
||||||
|
/* bypassSecondaryLockScreen= */true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -85,7 +85,8 @@ public class KeyguardHostView extends FrameLayout implements SecurityCallback {
|
|||||||
// the user proved presence via some other way to the trust agent.
|
// the user proved presence via some other way to the trust agent.
|
||||||
Log.i(TAG, "TrustAgent dismissed Keyguard.");
|
Log.i(TAG, "TrustAgent dismissed Keyguard.");
|
||||||
}
|
}
|
||||||
dismiss(false /* authenticated */, userId);
|
dismiss(false /* authenticated */, userId,
|
||||||
|
/* bypassSecondaryLockScreen */ false);
|
||||||
} else {
|
} else {
|
||||||
mViewMediatorCallback.playTrustedSound();
|
mViewMediatorCallback.playTrustedSound();
|
||||||
}
|
}
|
||||||
@@ -190,7 +191,7 @@ public class KeyguardHostView extends FrameLayout implements SecurityCallback {
|
|||||||
* @return True if the keyguard is done.
|
* @return True if the keyguard is done.
|
||||||
*/
|
*/
|
||||||
public boolean dismiss(int targetUserId) {
|
public boolean dismiss(int targetUserId) {
|
||||||
return dismiss(false, targetUserId);
|
return dismiss(false, targetUserId, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean handleBackKey() {
|
public boolean handleBackKey() {
|
||||||
@@ -206,8 +207,10 @@ public class KeyguardHostView extends FrameLayout implements SecurityCallback {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean dismiss(boolean authenticated, int targetUserId) {
|
public boolean dismiss(boolean authenticated, int targetUserId,
|
||||||
return mSecurityContainer.showNextSecurityScreenOrFinish(authenticated, targetUserId);
|
boolean bypassSecondaryLockScreen) {
|
||||||
|
return mSecurityContainer.showNextSecurityScreenOrFinish(authenticated, targetUserId,
|
||||||
|
bypassSecondaryLockScreen);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -24,6 +24,15 @@ public interface KeyguardSecurityCallback {
|
|||||||
*/
|
*/
|
||||||
void dismiss(boolean securityVerified, int targetUserId);
|
void dismiss(boolean securityVerified, int targetUserId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dismiss the given security screen.
|
||||||
|
* @param securityVerified true if the user correctly entered credentials for the given screen.
|
||||||
|
* @param targetUserId a user that needs to be the foreground user at the dismissal completion.
|
||||||
|
* @param bypassSecondaryLockScreen true if the user can bypass the secondary lock screen,
|
||||||
|
* if any, during this dismissal.
|
||||||
|
*/
|
||||||
|
void dismiss(boolean securityVerified, int targetUserId, boolean bypassSecondaryLockScreen);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Manually report user activity to keep the device awake.
|
* Manually report user activity to keep the device awake.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -115,7 +115,8 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe
|
|||||||
|
|
||||||
// Used to notify the container when something interesting happens.
|
// Used to notify the container when something interesting happens.
|
||||||
public interface SecurityCallback {
|
public interface SecurityCallback {
|
||||||
public boolean dismiss(boolean authenticated, int targetUserId);
|
public boolean dismiss(boolean authenticated, int targetUserId,
|
||||||
|
boolean bypassSecondaryLockScreen);
|
||||||
public void userActivity();
|
public void userActivity();
|
||||||
public void onSecurityModeChanged(SecurityMode securityMode, boolean needsInput);
|
public void onSecurityModeChanged(SecurityMode securityMode, boolean needsInput);
|
||||||
|
|
||||||
@@ -504,9 +505,12 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe
|
|||||||
* @param authenticated true if the user entered the correct authentication
|
* @param authenticated true if the user entered the correct authentication
|
||||||
* @param targetUserId a user that needs to be the foreground user at the finish (if called)
|
* @param targetUserId a user that needs to be the foreground user at the finish (if called)
|
||||||
* completion.
|
* completion.
|
||||||
|
* @param bypassSecondaryLockScreen true if the user is allowed to bypass the secondary
|
||||||
|
* secondary lock screen requirement, if any.
|
||||||
* @return true if keyguard is done
|
* @return true if keyguard is done
|
||||||
*/
|
*/
|
||||||
boolean showNextSecurityScreenOrFinish(boolean authenticated, int targetUserId) {
|
boolean showNextSecurityScreenOrFinish(boolean authenticated, int targetUserId,
|
||||||
|
boolean bypassSecondaryLockScreen) {
|
||||||
if (DEBUG) Log.d(TAG, "showNextSecurityScreenOrFinish(" + authenticated + ")");
|
if (DEBUG) Log.d(TAG, "showNextSecurityScreenOrFinish(" + authenticated + ")");
|
||||||
boolean finish = false;
|
boolean finish = false;
|
||||||
boolean strongAuth = false;
|
boolean strongAuth = false;
|
||||||
@@ -555,7 +559,7 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Check for device admin specified additional security measures.
|
// Check for device admin specified additional security measures.
|
||||||
if (finish) {
|
if (finish && !bypassSecondaryLockScreen) {
|
||||||
Intent secondaryLockscreenIntent =
|
Intent secondaryLockscreenIntent =
|
||||||
mUpdateMonitor.getSecondaryLockscreenRequirement(targetUserId);
|
mUpdateMonitor.getSecondaryLockscreenRequirement(targetUserId);
|
||||||
if (secondaryLockscreenIntent != null) {
|
if (secondaryLockscreenIntent != null) {
|
||||||
@@ -636,8 +640,15 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe
|
|||||||
mUpdateMonitor.cancelFaceAuth();
|
mUpdateMonitor.cancelFaceAuth();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void dismiss(boolean authenticated, int targetId) {
|
public void dismiss(boolean authenticated, int targetId) {
|
||||||
mSecurityCallback.dismiss(authenticated, targetId);
|
dismiss(authenticated, targetId, /* bypassSecondaryLockScreen */ false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void dismiss(boolean authenticated, int targetId,
|
||||||
|
boolean bypassSecondaryLockScreen) {
|
||||||
|
mSecurityCallback.dismiss(authenticated, targetId, bypassSecondaryLockScreen);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isVerifyUnlockOnly() {
|
public boolean isVerifyUnlockOnly() {
|
||||||
@@ -689,6 +700,9 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe
|
|||||||
@Override
|
@Override
|
||||||
public void dismiss(boolean securityVerified, int targetUserId) { }
|
public void dismiss(boolean securityVerified, int targetUserId) { }
|
||||||
@Override
|
@Override
|
||||||
|
public void dismiss(boolean authenticated, int targetId,
|
||||||
|
boolean bypassSecondaryLockScreen) { }
|
||||||
|
@Override
|
||||||
public void onUserInput() { }
|
public void onUserInput() { }
|
||||||
@Override
|
@Override
|
||||||
public void reset() {}
|
public void reset() {}
|
||||||
|
|||||||
@@ -115,6 +115,7 @@ public class AdminSecondaryLockScreenControllerTest extends SysuiTestCase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testShow_dismissedByCallback() throws Exception {
|
public void testShow_dismissedByCallback() throws Exception {
|
||||||
|
doAnswer(answerVoid(Runnable::run)).when(mHandler).post(any(Runnable.class));
|
||||||
doAnswer(invocation -> {
|
doAnswer(invocation -> {
|
||||||
IKeyguardCallback callback = (IKeyguardCallback) invocation.getArguments()[1];
|
IKeyguardCallback callback = (IKeyguardCallback) invocation.getArguments()[1];
|
||||||
callback.onDismiss();
|
callback.onDismiss();
|
||||||
@@ -184,7 +185,7 @@ public class AdminSecondaryLockScreenControllerTest extends SysuiTestCase {
|
|||||||
|
|
||||||
private void verifyViewDismissed(SurfaceView v) throws Exception {
|
private void verifyViewDismissed(SurfaceView v) throws Exception {
|
||||||
verify(mParent).removeView(v);
|
verify(mParent).removeView(v);
|
||||||
verify(mKeyguardCallback).dismiss(true, TARGET_USER_ID);
|
verify(mKeyguardCallback).dismiss(true, TARGET_USER_ID, true);
|
||||||
assertThat(mContext.isBound(mComponentName)).isFalse();
|
assertThat(mContext.isBound(mComponentName)).isFalse();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user