blob: 9dd97170437d12016afe9c502f1a29ebc706257f [file] [log] [blame]
Jim Miller31921482013-11-06 20:43:55 -08001/*
2 * Copyright (C) 2013 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package com.android.keyguard;
17
wilsonshihe7903ea2018-09-26 16:17:59 +080018import static android.view.Display.DEFAULT_DISPLAY;
David Stevens53a39ea2017-08-23 18:41:49 -070019
Jim Miller31921482013-11-06 20:43:55 -080020import android.app.Presentation;
21import android.content.Context;
Jim Miller31921482013-11-06 20:43:55 -080022import android.graphics.Point;
wilsonshihe7903ea2018-09-26 16:17:59 +080023import android.hardware.display.DisplayManager;
Jim Miller31921482013-11-06 20:43:55 -080024import android.media.MediaRouter;
25import android.media.MediaRouter.RouteInfo;
26import android.os.Bundle;
wilsonshihe7903ea2018-09-26 16:17:59 +080027import android.util.Log;
28import android.util.SparseArray;
Jim Miller31921482013-11-06 20:43:55 -080029import android.view.Display;
wilsonshihb5d1ab92018-12-06 12:52:31 +080030import android.view.DisplayInfo;
Jim Miller31921482013-11-06 20:43:55 -080031import android.view.View;
32import android.view.WindowManager;
33
David Stevens53a39ea2017-08-23 18:41:49 -070034// TODO(multi-display): Support multiple external displays
Jim Miller31921482013-11-06 20:43:55 -080035public class KeyguardDisplayManager {
36 protected static final String TAG = "KeyguardDisplayManager";
Jorim Jaggi5cf17872014-03-26 18:31:48 +010037 private static boolean DEBUG = KeyguardConstants.DEBUG;
David Stevens53a39ea2017-08-23 18:41:49 -070038
David Stevens53a39ea2017-08-23 18:41:49 -070039 private final MediaRouter mMediaRouter;
wilsonshihe7903ea2018-09-26 16:17:59 +080040 private final DisplayManager mDisplayService;
David Stevens53a39ea2017-08-23 18:41:49 -070041 private final Context mContext;
42
Jim Miller31921482013-11-06 20:43:55 -080043 private boolean mShowing;
wilsonshihb5d1ab92018-12-06 12:52:31 +080044 private final DisplayInfo mTmpDisplayInfo = new DisplayInfo();
Jim Miller31921482013-11-06 20:43:55 -080045
wilsonshihe7903ea2018-09-26 16:17:59 +080046 private final SparseArray<Presentation> mPresentations = new SparseArray<>();
47
48 private final DisplayManager.DisplayListener mDisplayListener =
49 new DisplayManager.DisplayListener() {
50
51 @Override
52 public void onDisplayAdded(int displayId) {
53 final Display display = mDisplayService.getDisplay(displayId);
54 if (mShowing) {
wilsonshih177261f2019-02-22 12:02:18 +080055 showPresentation(display);
wilsonshihe7903ea2018-09-26 16:17:59 +080056 }
57 }
58
59 @Override
60 public void onDisplayChanged(int displayId) {
61 if (displayId == DEFAULT_DISPLAY) return;
62 final Display display = mDisplayService.getDisplay(displayId);
63 if (display != null && mShowing) {
64 final Presentation presentation = mPresentations.get(displayId);
65 if (presentation != null && !presentation.getDisplay().equals(display)) {
66 hidePresentation(displayId);
67 showPresentation(display);
68 }
69 }
70 }
71
72 @Override
73 public void onDisplayRemoved(int displayId) {
wilsonshih177261f2019-02-22 12:02:18 +080074 hidePresentation(displayId);
wilsonshihe7903ea2018-09-26 16:17:59 +080075 }
76 };
77
wilsonshih177261f2019-02-22 12:02:18 +080078 public KeyguardDisplayManager(Context context) {
Jim Miller31921482013-11-06 20:43:55 -080079 mContext = context;
wilsonshihe7903ea2018-09-26 16:17:59 +080080 mMediaRouter = mContext.getSystemService(MediaRouter.class);
81 mDisplayService = mContext.getSystemService(DisplayManager.class);
82 mDisplayService.registerDisplayListener(mDisplayListener, null /* handler */);
83 }
84
wilsonshihb5d1ab92018-12-06 12:52:31 +080085 private boolean isKeyguardShowable(Display display) {
86 if (display == null) {
87 if (DEBUG) Log.i(TAG, "Cannot show Keyguard on null display");
88 return false;
89 }
90 if (display.getDisplayId() == DEFAULT_DISPLAY) {
91 if (DEBUG) Log.i(TAG, "Do not show KeyguardPresentation on the default display");
92 return false;
93 }
94 display.getDisplayInfo(mTmpDisplayInfo);
95 if ((mTmpDisplayInfo.flags & Display.FLAG_PRIVATE) != 0) {
96 if (DEBUG) Log.i(TAG, "Do not show KeyguardPresentation on a private display");
97 return false;
98 }
99 return true;
100 }
wilsonshihe7903ea2018-09-26 16:17:59 +0800101 /**
102 * @param display The display to show the presentation on.
103 * @return {@code true} if a presentation was added.
104 * {@code false} if the presentation cannot be added on that display or the presentation
105 * was already there.
106 */
107 private boolean showPresentation(Display display) {
wilsonshihb5d1ab92018-12-06 12:52:31 +0800108 if (!isKeyguardShowable(display)) return false;
wilsonshihe7903ea2018-09-26 16:17:59 +0800109 if (DEBUG) Log.i(TAG, "Keyguard enabled on display: " + display);
110 final int displayId = display.getDisplayId();
111 Presentation presentation = mPresentations.get(displayId);
112 if (presentation == null) {
113 presentation = new KeyguardPresentation(mContext, display);
114 presentation.setOnDismissListener(dialog -> {
115 if (null != mPresentations.get(displayId)) {
116 mPresentations.remove(displayId);
117 }
118 });
119 try {
120 presentation.show();
121 } catch (WindowManager.InvalidDisplayException ex) {
122 Log.w(TAG, "Invalid display:", ex);
123 presentation = null;
124 }
125 if (presentation != null) {
126 mPresentations.append(displayId, presentation);
127 return true;
128 }
129 }
130 return false;
131 }
132
133 /**
134 * @param displayId The id of the display to hide the presentation off.
wilsonshihe7903ea2018-09-26 16:17:59 +0800135 */
wilsonshih177261f2019-02-22 12:02:18 +0800136 private void hidePresentation(int displayId) {
wilsonshihe7903ea2018-09-26 16:17:59 +0800137 final Presentation presentation = mPresentations.get(displayId);
138 if (presentation != null) {
139 presentation.dismiss();
140 mPresentations.remove(displayId);
wilsonshihe7903ea2018-09-26 16:17:59 +0800141 }
Jim Miller31921482013-11-06 20:43:55 -0800142 }
143
Jorim Jaggi5cf17872014-03-26 18:31:48 +0100144 public void show() {
Jim Miller31921482013-11-06 20:43:55 -0800145 if (!mShowing) {
wilsonshihe7903ea2018-09-26 16:17:59 +0800146 if (DEBUG) Log.v(TAG, "show");
Jim Miller31921482013-11-06 20:43:55 -0800147 mMediaRouter.addCallback(MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY,
148 mMediaRouterCallback, MediaRouter.CALLBACK_FLAG_PASSIVE_DISCOVERY);
wilsonshih177261f2019-02-22 12:02:18 +0800149 updateDisplays(true /* showing */);
Jim Miller31921482013-11-06 20:43:55 -0800150 }
151 mShowing = true;
152 }
153
Jorim Jaggi5cf17872014-03-26 18:31:48 +0100154 public void hide() {
Jim Miller31921482013-11-06 20:43:55 -0800155 if (mShowing) {
wilsonshihe7903ea2018-09-26 16:17:59 +0800156 if (DEBUG) Log.v(TAG, "hide");
Jim Miller31921482013-11-06 20:43:55 -0800157 mMediaRouter.removeCallback(mMediaRouterCallback);
wilsonshih177261f2019-02-22 12:02:18 +0800158 updateDisplays(false /* showing */);
Jim Miller31921482013-11-06 20:43:55 -0800159 }
160 mShowing = false;
161 }
162
163 private final MediaRouter.SimpleCallback mMediaRouterCallback =
164 new MediaRouter.SimpleCallback() {
165 @Override
166 public void onRouteSelected(MediaRouter router, int type, RouteInfo info) {
wilsonshihe7903ea2018-09-26 16:17:59 +0800167 if (DEBUG) Log.d(TAG, "onRouteSelected: type=" + type + ", info=" + info);
wilsonshih177261f2019-02-22 12:02:18 +0800168 updateDisplays(mShowing);
Jim Miller31921482013-11-06 20:43:55 -0800169 }
170
171 @Override
172 public void onRouteUnselected(MediaRouter router, int type, RouteInfo info) {
wilsonshihe7903ea2018-09-26 16:17:59 +0800173 if (DEBUG) Log.d(TAG, "onRouteUnselected: type=" + type + ", info=" + info);
wilsonshih177261f2019-02-22 12:02:18 +0800174 updateDisplays(mShowing);
Jim Miller31921482013-11-06 20:43:55 -0800175 }
176
177 @Override
178 public void onRoutePresentationDisplayChanged(MediaRouter router, RouteInfo info) {
wilsonshihe7903ea2018-09-26 16:17:59 +0800179 if (DEBUG) Log.d(TAG, "onRoutePresentationDisplayChanged: info=" + info);
wilsonshih177261f2019-02-22 12:02:18 +0800180 updateDisplays(mShowing);
Jim Miller31921482013-11-06 20:43:55 -0800181 }
182 };
183
wilsonshihe7903ea2018-09-26 16:17:59 +0800184 protected boolean updateDisplays(boolean showing) {
185 boolean changed = false;
Jim Miller31921482013-11-06 20:43:55 -0800186 if (showing) {
wilsonshihe7903ea2018-09-26 16:17:59 +0800187 final Display[] displays = mDisplayService.getDisplays();
188 for (Display display : displays) {
189 changed |= showPresentation(display);
Jim Miller31921482013-11-06 20:43:55 -0800190 }
191 } else {
wilsonshihe7903ea2018-09-26 16:17:59 +0800192 changed = mPresentations.size() > 0;
193 for (int i = mPresentations.size() - 1; i >= 0; i--) {
194 mPresentations.valueAt(i).dismiss();
Jim Miller31921482013-11-06 20:43:55 -0800195 }
wilsonshihe7903ea2018-09-26 16:17:59 +0800196 mPresentations.clear();
Jim Miller31921482013-11-06 20:43:55 -0800197 }
wilsonshihe7903ea2018-09-26 16:17:59 +0800198 return changed;
Jim Miller31921482013-11-06 20:43:55 -0800199 }
200
201 private final static class KeyguardPresentation extends Presentation {
202 private static final int VIDEO_SAFE_REGION = 80; // Percentage of display width & height
203 private static final int MOVE_CLOCK_TIMEOUT = 10000; // 10s
204 private View mClock;
205 private int mUsableWidth;
206 private int mUsableHeight;
207 private int mMarginTop;
208 private int mMarginLeft;
209 Runnable mMoveTextRunnable = new Runnable() {
210 @Override
211 public void run() {
212 int x = mMarginLeft + (int) (Math.random() * (mUsableWidth - mClock.getWidth()));
213 int y = mMarginTop + (int) (Math.random() * (mUsableHeight - mClock.getHeight()));
214 mClock.setTranslationX(x);
215 mClock.setTranslationY(y);
216 mClock.postDelayed(mMoveTextRunnable, MOVE_CLOCK_TIMEOUT);
217 }
218 };
219
wilsonshihe7903ea2018-09-26 16:17:59 +0800220 KeyguardPresentation(Context context, Display display) {
221 super(context, display, R.style.keyguard_presentation_theme);
Jim Miller31921482013-11-06 20:43:55 -0800222 getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
wilsonshihe7903ea2018-09-26 16:17:59 +0800223 setCancelable(false);
Jim Miller31921482013-11-06 20:43:55 -0800224 }
225
Jim Millerc90d6452015-07-06 18:17:34 -0700226 @Override
Jim Miller31921482013-11-06 20:43:55 -0800227 public void onDetachedFromWindow() {
228 mClock.removeCallbacks(mMoveTextRunnable);
229 }
230
231 @Override
232 protected void onCreate(Bundle savedInstanceState) {
233 super.onCreate(savedInstanceState);
234
235 Point p = new Point();
236 getDisplay().getSize(p);
237 mUsableWidth = VIDEO_SAFE_REGION * p.x/100;
238 mUsableHeight = VIDEO_SAFE_REGION * p.y/100;
239 mMarginLeft = (100 - VIDEO_SAFE_REGION) * p.x / 200;
240 mMarginTop = (100 - VIDEO_SAFE_REGION) * p.y / 200;
241
242 setContentView(R.layout.keyguard_presentation);
243 mClock = findViewById(R.id.clock);
244
245 // Avoid screen burn in
246 mClock.post(mMoveTextRunnable);
247 }
248 }
249}