blob: ae8bc528ab6ac67643177c17816c69a3027d9996 [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;
Robert Snoebergerbe35b762019-03-15 14:33:02 -040031import android.view.LayoutInflater;
Jim Miller31921482013-11-06 20:43:55 -080032import android.view.View;
33import android.view.WindowManager;
34
Robert Snoebergerbe35b762019-03-15 14:33:02 -040035import com.android.systemui.util.InjectionInflationController;
36
David Stevens53a39ea2017-08-23 18:41:49 -070037// TODO(multi-display): Support multiple external displays
Jim Miller31921482013-11-06 20:43:55 -080038public class KeyguardDisplayManager {
39 protected static final String TAG = "KeyguardDisplayManager";
Jorim Jaggi5cf17872014-03-26 18:31:48 +010040 private static boolean DEBUG = KeyguardConstants.DEBUG;
David Stevens53a39ea2017-08-23 18:41:49 -070041
David Stevens53a39ea2017-08-23 18:41:49 -070042 private final MediaRouter mMediaRouter;
wilsonshihe7903ea2018-09-26 16:17:59 +080043 private final DisplayManager mDisplayService;
Robert Snoebergerbe35b762019-03-15 14:33:02 -040044 private final InjectionInflationController mInjectableInflater;
David Stevens53a39ea2017-08-23 18:41:49 -070045 private final Context mContext;
46
Jim Miller31921482013-11-06 20:43:55 -080047 private boolean mShowing;
wilsonshihb5d1ab92018-12-06 12:52:31 +080048 private final DisplayInfo mTmpDisplayInfo = new DisplayInfo();
Jim Miller31921482013-11-06 20:43:55 -080049
wilsonshihe7903ea2018-09-26 16:17:59 +080050 private final SparseArray<Presentation> mPresentations = new SparseArray<>();
51
52 private final DisplayManager.DisplayListener mDisplayListener =
53 new DisplayManager.DisplayListener() {
54
55 @Override
56 public void onDisplayAdded(int displayId) {
57 final Display display = mDisplayService.getDisplay(displayId);
58 if (mShowing) {
wilsonshih177261f2019-02-22 12:02:18 +080059 showPresentation(display);
wilsonshihe7903ea2018-09-26 16:17:59 +080060 }
61 }
62
63 @Override
64 public void onDisplayChanged(int displayId) {
65 if (displayId == DEFAULT_DISPLAY) return;
66 final Display display = mDisplayService.getDisplay(displayId);
67 if (display != null && mShowing) {
68 final Presentation presentation = mPresentations.get(displayId);
69 if (presentation != null && !presentation.getDisplay().equals(display)) {
70 hidePresentation(displayId);
71 showPresentation(display);
72 }
73 }
74 }
75
76 @Override
77 public void onDisplayRemoved(int displayId) {
wilsonshih177261f2019-02-22 12:02:18 +080078 hidePresentation(displayId);
wilsonshihe7903ea2018-09-26 16:17:59 +080079 }
80 };
81
Robert Snoebergerbe35b762019-03-15 14:33:02 -040082 public KeyguardDisplayManager(Context context,
83 InjectionInflationController injectableInflater) {
Jim Miller31921482013-11-06 20:43:55 -080084 mContext = context;
Robert Snoebergerbe35b762019-03-15 14:33:02 -040085 mInjectableInflater = injectableInflater;
wilsonshihe7903ea2018-09-26 16:17:59 +080086 mMediaRouter = mContext.getSystemService(MediaRouter.class);
87 mDisplayService = mContext.getSystemService(DisplayManager.class);
88 mDisplayService.registerDisplayListener(mDisplayListener, null /* handler */);
89 }
90
wilsonshihb5d1ab92018-12-06 12:52:31 +080091 private boolean isKeyguardShowable(Display display) {
92 if (display == null) {
93 if (DEBUG) Log.i(TAG, "Cannot show Keyguard on null display");
94 return false;
95 }
96 if (display.getDisplayId() == DEFAULT_DISPLAY) {
97 if (DEBUG) Log.i(TAG, "Do not show KeyguardPresentation on the default display");
98 return false;
99 }
100 display.getDisplayInfo(mTmpDisplayInfo);
101 if ((mTmpDisplayInfo.flags & Display.FLAG_PRIVATE) != 0) {
102 if (DEBUG) Log.i(TAG, "Do not show KeyguardPresentation on a private display");
103 return false;
104 }
105 return true;
106 }
wilsonshihe7903ea2018-09-26 16:17:59 +0800107 /**
108 * @param display The display to show the presentation on.
109 * @return {@code true} if a presentation was added.
110 * {@code false} if the presentation cannot be added on that display or the presentation
111 * was already there.
112 */
113 private boolean showPresentation(Display display) {
wilsonshihb5d1ab92018-12-06 12:52:31 +0800114 if (!isKeyguardShowable(display)) return false;
wilsonshihe7903ea2018-09-26 16:17:59 +0800115 if (DEBUG) Log.i(TAG, "Keyguard enabled on display: " + display);
116 final int displayId = display.getDisplayId();
117 Presentation presentation = mPresentations.get(displayId);
118 if (presentation == null) {
Robert Snoebergerbe35b762019-03-15 14:33:02 -0400119 presentation = new KeyguardPresentation(mContext, display, mInjectableInflater);
wilsonshihe7903ea2018-09-26 16:17:59 +0800120 presentation.setOnDismissListener(dialog -> {
121 if (null != mPresentations.get(displayId)) {
122 mPresentations.remove(displayId);
123 }
124 });
125 try {
126 presentation.show();
127 } catch (WindowManager.InvalidDisplayException ex) {
128 Log.w(TAG, "Invalid display:", ex);
129 presentation = null;
130 }
131 if (presentation != null) {
132 mPresentations.append(displayId, presentation);
133 return true;
134 }
135 }
136 return false;
137 }
138
139 /**
140 * @param displayId The id of the display to hide the presentation off.
wilsonshihe7903ea2018-09-26 16:17:59 +0800141 */
wilsonshih177261f2019-02-22 12:02:18 +0800142 private void hidePresentation(int displayId) {
wilsonshihe7903ea2018-09-26 16:17:59 +0800143 final Presentation presentation = mPresentations.get(displayId);
144 if (presentation != null) {
145 presentation.dismiss();
146 mPresentations.remove(displayId);
wilsonshihe7903ea2018-09-26 16:17:59 +0800147 }
Jim Miller31921482013-11-06 20:43:55 -0800148 }
149
Jorim Jaggi5cf17872014-03-26 18:31:48 +0100150 public void show() {
Jim Miller31921482013-11-06 20:43:55 -0800151 if (!mShowing) {
wilsonshihe7903ea2018-09-26 16:17:59 +0800152 if (DEBUG) Log.v(TAG, "show");
Jim Miller31921482013-11-06 20:43:55 -0800153 mMediaRouter.addCallback(MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY,
154 mMediaRouterCallback, MediaRouter.CALLBACK_FLAG_PASSIVE_DISCOVERY);
wilsonshih177261f2019-02-22 12:02:18 +0800155 updateDisplays(true /* showing */);
Jim Miller31921482013-11-06 20:43:55 -0800156 }
157 mShowing = true;
158 }
159
Jorim Jaggi5cf17872014-03-26 18:31:48 +0100160 public void hide() {
Jim Miller31921482013-11-06 20:43:55 -0800161 if (mShowing) {
wilsonshihe7903ea2018-09-26 16:17:59 +0800162 if (DEBUG) Log.v(TAG, "hide");
Jim Miller31921482013-11-06 20:43:55 -0800163 mMediaRouter.removeCallback(mMediaRouterCallback);
wilsonshih177261f2019-02-22 12:02:18 +0800164 updateDisplays(false /* showing */);
Jim Miller31921482013-11-06 20:43:55 -0800165 }
166 mShowing = false;
167 }
168
169 private final MediaRouter.SimpleCallback mMediaRouterCallback =
170 new MediaRouter.SimpleCallback() {
171 @Override
172 public void onRouteSelected(MediaRouter router, int type, RouteInfo info) {
wilsonshihe7903ea2018-09-26 16:17:59 +0800173 if (DEBUG) Log.d(TAG, "onRouteSelected: 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 onRouteUnselected(MediaRouter router, int type, RouteInfo info) {
wilsonshihe7903ea2018-09-26 16:17:59 +0800179 if (DEBUG) Log.d(TAG, "onRouteUnselected: type=" + type + ", info=" + info);
wilsonshih177261f2019-02-22 12:02:18 +0800180 updateDisplays(mShowing);
Jim Miller31921482013-11-06 20:43:55 -0800181 }
182
183 @Override
184 public void onRoutePresentationDisplayChanged(MediaRouter router, RouteInfo info) {
wilsonshihe7903ea2018-09-26 16:17:59 +0800185 if (DEBUG) Log.d(TAG, "onRoutePresentationDisplayChanged: info=" + info);
wilsonshih177261f2019-02-22 12:02:18 +0800186 updateDisplays(mShowing);
Jim Miller31921482013-11-06 20:43:55 -0800187 }
188 };
189
wilsonshihe7903ea2018-09-26 16:17:59 +0800190 protected boolean updateDisplays(boolean showing) {
191 boolean changed = false;
Jim Miller31921482013-11-06 20:43:55 -0800192 if (showing) {
wilsonshihe7903ea2018-09-26 16:17:59 +0800193 final Display[] displays = mDisplayService.getDisplays();
194 for (Display display : displays) {
195 changed |= showPresentation(display);
Jim Miller31921482013-11-06 20:43:55 -0800196 }
197 } else {
wilsonshihe7903ea2018-09-26 16:17:59 +0800198 changed = mPresentations.size() > 0;
199 for (int i = mPresentations.size() - 1; i >= 0; i--) {
200 mPresentations.valueAt(i).dismiss();
Jim Miller31921482013-11-06 20:43:55 -0800201 }
wilsonshihe7903ea2018-09-26 16:17:59 +0800202 mPresentations.clear();
Jim Miller31921482013-11-06 20:43:55 -0800203 }
wilsonshihe7903ea2018-09-26 16:17:59 +0800204 return changed;
Jim Miller31921482013-11-06 20:43:55 -0800205 }
206
207 private final static class KeyguardPresentation extends Presentation {
208 private static final int VIDEO_SAFE_REGION = 80; // Percentage of display width & height
209 private static final int MOVE_CLOCK_TIMEOUT = 10000; // 10s
Robert Snoebergerbe35b762019-03-15 14:33:02 -0400210 private final InjectionInflationController mInjectableInflater;
Jim Miller31921482013-11-06 20:43:55 -0800211 private View mClock;
212 private int mUsableWidth;
213 private int mUsableHeight;
214 private int mMarginTop;
215 private int mMarginLeft;
216 Runnable mMoveTextRunnable = new Runnable() {
217 @Override
218 public void run() {
219 int x = mMarginLeft + (int) (Math.random() * (mUsableWidth - mClock.getWidth()));
220 int y = mMarginTop + (int) (Math.random() * (mUsableHeight - mClock.getHeight()));
221 mClock.setTranslationX(x);
222 mClock.setTranslationY(y);
223 mClock.postDelayed(mMoveTextRunnable, MOVE_CLOCK_TIMEOUT);
224 }
225 };
226
Robert Snoebergerbe35b762019-03-15 14:33:02 -0400227 KeyguardPresentation(Context context, Display display,
228 InjectionInflationController injectionInflater) {
wilsonshihe7903ea2018-09-26 16:17:59 +0800229 super(context, display, R.style.keyguard_presentation_theme);
Robert Snoebergerbe35b762019-03-15 14:33:02 -0400230 mInjectableInflater = injectionInflater;
Jim Miller31921482013-11-06 20:43:55 -0800231 getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
wilsonshihe7903ea2018-09-26 16:17:59 +0800232 setCancelable(false);
Jim Miller31921482013-11-06 20:43:55 -0800233 }
234
Jim Millerc90d6452015-07-06 18:17:34 -0700235 @Override
Jim Miller31921482013-11-06 20:43:55 -0800236 public void onDetachedFromWindow() {
237 mClock.removeCallbacks(mMoveTextRunnable);
238 }
239
240 @Override
241 protected void onCreate(Bundle savedInstanceState) {
242 super.onCreate(savedInstanceState);
243
244 Point p = new Point();
245 getDisplay().getSize(p);
246 mUsableWidth = VIDEO_SAFE_REGION * p.x/100;
247 mUsableHeight = VIDEO_SAFE_REGION * p.y/100;
248 mMarginLeft = (100 - VIDEO_SAFE_REGION) * p.x / 200;
249 mMarginTop = (100 - VIDEO_SAFE_REGION) * p.y / 200;
250
Robert Snoebergerbe35b762019-03-15 14:33:02 -0400251 LayoutInflater inflater = mInjectableInflater.injectable(
252 LayoutInflater.from(getContext()));
253 setContentView(inflater.inflate(R.layout.keyguard_presentation, null));
Jim Miller31921482013-11-06 20:43:55 -0800254 mClock = findViewById(R.id.clock);
255
256 // Avoid screen burn in
257 mClock.post(mMoveTextRunnable);
258 }
259 }
260}