The keyguard has windows on the default display and the remote display selected by MediaRouter. Keyguard occlusion only applies to the default display. To make the activity showWhenLocked flag work on secondary displays, pass the display id of the locked secondary display from the SystemUi to KeyguardController and make its isKeyguardShowing method take a displayId. Test: android.server.cts.ActivityManagerDisplayTests Test: #testSecondaryDisplayShowWhenLocked Bug: 64994006 Merged-In: Ib31fc76e9df469e97a59a181f09d457ceed4ef5f Change-Id: Ib31fc76e9df469e97a59a181f09d457ceed4ef5f
189 lines
7.1 KiB
Java
189 lines
7.1 KiB
Java
/*
|
|
* Copyright (C) 2013 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 com.android.keyguard;
|
|
|
|
import static android.view.Display.INVALID_DISPLAY;
|
|
|
|
import android.app.Presentation;
|
|
import android.content.Context;
|
|
import android.content.DialogInterface;
|
|
import android.content.DialogInterface.OnDismissListener;
|
|
import android.graphics.Point;
|
|
import android.media.MediaRouter;
|
|
import android.media.MediaRouter.RouteInfo;
|
|
import android.os.Bundle;
|
|
import android.util.Slog;
|
|
import android.view.Display;
|
|
import android.view.View;
|
|
import android.view.WindowManager;
|
|
|
|
// TODO(multi-display): Support multiple external displays
|
|
public class KeyguardDisplayManager {
|
|
protected static final String TAG = "KeyguardDisplayManager";
|
|
private static boolean DEBUG = KeyguardConstants.DEBUG;
|
|
|
|
private final ViewMediatorCallback mCallback;
|
|
private final MediaRouter mMediaRouter;
|
|
private final Context mContext;
|
|
|
|
Presentation mPresentation;
|
|
private boolean mShowing;
|
|
|
|
public KeyguardDisplayManager(Context context, ViewMediatorCallback callback) {
|
|
mContext = context;
|
|
mCallback = callback;
|
|
mMediaRouter = (MediaRouter) mContext.getSystemService(Context.MEDIA_ROUTER_SERVICE);
|
|
}
|
|
|
|
public void show() {
|
|
if (!mShowing) {
|
|
if (DEBUG) Slog.v(TAG, "show");
|
|
mMediaRouter.addCallback(MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY,
|
|
mMediaRouterCallback, MediaRouter.CALLBACK_FLAG_PASSIVE_DISCOVERY);
|
|
updateDisplays(true);
|
|
}
|
|
mShowing = true;
|
|
}
|
|
|
|
public void hide() {
|
|
if (mShowing) {
|
|
if (DEBUG) Slog.v(TAG, "hide");
|
|
mMediaRouter.removeCallback(mMediaRouterCallback);
|
|
updateDisplays(false);
|
|
}
|
|
mShowing = false;
|
|
}
|
|
|
|
private final MediaRouter.SimpleCallback mMediaRouterCallback =
|
|
new MediaRouter.SimpleCallback() {
|
|
@Override
|
|
public void onRouteSelected(MediaRouter router, int type, RouteInfo info) {
|
|
if (DEBUG) Slog.d(TAG, "onRouteSelected: type=" + type + ", info=" + info);
|
|
updateDisplays(mShowing);
|
|
}
|
|
|
|
@Override
|
|
public void onRouteUnselected(MediaRouter router, int type, RouteInfo info) {
|
|
if (DEBUG) Slog.d(TAG, "onRouteUnselected: type=" + type + ", info=" + info);
|
|
updateDisplays(mShowing);
|
|
}
|
|
|
|
@Override
|
|
public void onRoutePresentationDisplayChanged(MediaRouter router, RouteInfo info) {
|
|
if (DEBUG) Slog.d(TAG, "onRoutePresentationDisplayChanged: info=" + info);
|
|
updateDisplays(mShowing);
|
|
}
|
|
};
|
|
|
|
private OnDismissListener mOnDismissListener = new OnDismissListener() {
|
|
|
|
@Override
|
|
public void onDismiss(DialogInterface dialog) {
|
|
mPresentation = null;
|
|
}
|
|
};
|
|
|
|
protected void updateDisplays(boolean showing) {
|
|
Presentation originalPresentation = mPresentation;
|
|
if (showing) {
|
|
MediaRouter.RouteInfo route = mMediaRouter.getSelectedRoute(
|
|
MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY);
|
|
boolean useDisplay = route != null
|
|
&& route.getPlaybackType() == MediaRouter.RouteInfo.PLAYBACK_TYPE_REMOTE;
|
|
Display presentationDisplay = useDisplay ? route.getPresentationDisplay() : null;
|
|
|
|
if (mPresentation != null && mPresentation.getDisplay() != presentationDisplay) {
|
|
if (DEBUG) Slog.v(TAG, "Display gone: " + mPresentation.getDisplay());
|
|
mPresentation.dismiss();
|
|
mPresentation = null;
|
|
}
|
|
|
|
if (mPresentation == null && presentationDisplay != null) {
|
|
if (DEBUG) Slog.i(TAG, "Keyguard enabled on display: " + presentationDisplay);
|
|
mPresentation = new KeyguardPresentation(mContext, presentationDisplay,
|
|
R.style.keyguard_presentation_theme);
|
|
mPresentation.setOnDismissListener(mOnDismissListener);
|
|
try {
|
|
mPresentation.show();
|
|
} catch (WindowManager.InvalidDisplayException ex) {
|
|
Slog.w(TAG, "Invalid display:", ex);
|
|
mPresentation = null;
|
|
}
|
|
}
|
|
} else {
|
|
if (mPresentation != null) {
|
|
mPresentation.dismiss();
|
|
mPresentation = null;
|
|
}
|
|
}
|
|
|
|
// mPresentation is only updated when the display changes
|
|
if (mPresentation != originalPresentation) {
|
|
final int displayId = mPresentation != null
|
|
? mPresentation.getDisplay().getDisplayId() : INVALID_DISPLAY;
|
|
mCallback.onSecondaryDisplayShowingChanged(displayId);
|
|
}
|
|
}
|
|
|
|
private final static class KeyguardPresentation extends Presentation {
|
|
private static final int VIDEO_SAFE_REGION = 80; // Percentage of display width & height
|
|
private static final int MOVE_CLOCK_TIMEOUT = 10000; // 10s
|
|
private View mClock;
|
|
private int mUsableWidth;
|
|
private int mUsableHeight;
|
|
private int mMarginTop;
|
|
private int mMarginLeft;
|
|
Runnable mMoveTextRunnable = new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
int x = mMarginLeft + (int) (Math.random() * (mUsableWidth - mClock.getWidth()));
|
|
int y = mMarginTop + (int) (Math.random() * (mUsableHeight - mClock.getHeight()));
|
|
mClock.setTranslationX(x);
|
|
mClock.setTranslationY(y);
|
|
mClock.postDelayed(mMoveTextRunnable, MOVE_CLOCK_TIMEOUT);
|
|
}
|
|
};
|
|
|
|
public KeyguardPresentation(Context context, Display display, int theme) {
|
|
super(context, display, theme);
|
|
getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
|
|
}
|
|
|
|
@Override
|
|
public void onDetachedFromWindow() {
|
|
mClock.removeCallbacks(mMoveTextRunnable);
|
|
}
|
|
|
|
@Override
|
|
protected void onCreate(Bundle savedInstanceState) {
|
|
super.onCreate(savedInstanceState);
|
|
|
|
Point p = new Point();
|
|
getDisplay().getSize(p);
|
|
mUsableWidth = VIDEO_SAFE_REGION * p.x/100;
|
|
mUsableHeight = VIDEO_SAFE_REGION * p.y/100;
|
|
mMarginLeft = (100 - VIDEO_SAFE_REGION) * p.x / 200;
|
|
mMarginTop = (100 - VIDEO_SAFE_REGION) * p.y / 200;
|
|
|
|
setContentView(R.layout.keyguard_presentation);
|
|
mClock = findViewById(R.id.clock);
|
|
|
|
// Avoid screen burn in
|
|
mClock.post(mMoveTextRunnable);
|
|
}
|
|
}
|
|
}
|