blob: 050655c79ffcc60f0c9c90fffe10967a2386204a [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;
Charles Chen64172bb2019-04-22 17:30:29 +080022import android.graphics.Color;
Jim Miller31921482013-11-06 20:43:55 -080023import android.graphics.Point;
wilsonshihe7903ea2018-09-26 16:17:59 +080024import android.hardware.display.DisplayManager;
Jim Miller31921482013-11-06 20:43:55 -080025import android.media.MediaRouter;
26import android.media.MediaRouter.RouteInfo;
27import android.os.Bundle;
wilsonshihe7903ea2018-09-26 16:17:59 +080028import android.util.Log;
29import android.util.SparseArray;
Jim Miller31921482013-11-06 20:43:55 -080030import android.view.Display;
wilsonshihb5d1ab92018-12-06 12:52:31 +080031import android.view.DisplayInfo;
Robert Snoebergerbe35b762019-03-15 14:33:02 -040032import android.view.LayoutInflater;
Jim Miller31921482013-11-06 20:43:55 -080033import android.view.View;
34import android.view.WindowManager;
35
Charles Chen64172bb2019-04-22 17:30:29 +080036import com.android.systemui.Dependency;
37import com.android.systemui.statusbar.NavigationBarController;
38import com.android.systemui.statusbar.phone.NavigationBarView;
Robert Snoebergerbe35b762019-03-15 14:33:02 -040039import com.android.systemui.util.InjectionInflationController;
40
Jim Miller31921482013-11-06 20:43:55 -080041public class KeyguardDisplayManager {
42 protected static final String TAG = "KeyguardDisplayManager";
Jorim Jaggi5cf17872014-03-26 18:31:48 +010043 private static boolean DEBUG = KeyguardConstants.DEBUG;
David Stevens53a39ea2017-08-23 18:41:49 -070044
David Stevens53a39ea2017-08-23 18:41:49 -070045 private final MediaRouter mMediaRouter;
wilsonshihe7903ea2018-09-26 16:17:59 +080046 private final DisplayManager mDisplayService;
Robert Snoebergerbe35b762019-03-15 14:33:02 -040047 private final InjectionInflationController mInjectableInflater;
David Stevens53a39ea2017-08-23 18:41:49 -070048 private final Context mContext;
49
Jim Miller31921482013-11-06 20:43:55 -080050 private boolean mShowing;
wilsonshihb5d1ab92018-12-06 12:52:31 +080051 private final DisplayInfo mTmpDisplayInfo = new DisplayInfo();
Jim Miller31921482013-11-06 20:43:55 -080052
wilsonshihe7903ea2018-09-26 16:17:59 +080053 private final SparseArray<Presentation> mPresentations = new SparseArray<>();
54
Charles Chen64172bb2019-04-22 17:30:29 +080055 private final NavigationBarController mNavBarController =
56 Dependency.get(NavigationBarController.class);
57
wilsonshihe7903ea2018-09-26 16:17:59 +080058 private final DisplayManager.DisplayListener mDisplayListener =
59 new DisplayManager.DisplayListener() {
60
61 @Override
62 public void onDisplayAdded(int displayId) {
63 final Display display = mDisplayService.getDisplay(displayId);
64 if (mShowing) {
Charles Chen64172bb2019-04-22 17:30:29 +080065 updateNavigationBarVisibility(displayId, false /* navBarVisible */);
wilsonshih177261f2019-02-22 12:02:18 +080066 showPresentation(display);
wilsonshihe7903ea2018-09-26 16:17:59 +080067 }
68 }
69
70 @Override
71 public void onDisplayChanged(int displayId) {
72 if (displayId == DEFAULT_DISPLAY) return;
73 final Display display = mDisplayService.getDisplay(displayId);
74 if (display != null && mShowing) {
75 final Presentation presentation = mPresentations.get(displayId);
76 if (presentation != null && !presentation.getDisplay().equals(display)) {
77 hidePresentation(displayId);
78 showPresentation(display);
79 }
80 }
81 }
82
83 @Override
84 public void onDisplayRemoved(int displayId) {
wilsonshih177261f2019-02-22 12:02:18 +080085 hidePresentation(displayId);
wilsonshihe7903ea2018-09-26 16:17:59 +080086 }
87 };
88
Robert Snoebergerbe35b762019-03-15 14:33:02 -040089 public KeyguardDisplayManager(Context context,
90 InjectionInflationController injectableInflater) {
Jim Miller31921482013-11-06 20:43:55 -080091 mContext = context;
Robert Snoebergerbe35b762019-03-15 14:33:02 -040092 mInjectableInflater = injectableInflater;
wilsonshihe7903ea2018-09-26 16:17:59 +080093 mMediaRouter = mContext.getSystemService(MediaRouter.class);
94 mDisplayService = mContext.getSystemService(DisplayManager.class);
95 mDisplayService.registerDisplayListener(mDisplayListener, null /* handler */);
96 }
97
wilsonshihb5d1ab92018-12-06 12:52:31 +080098 private boolean isKeyguardShowable(Display display) {
99 if (display == null) {
100 if (DEBUG) Log.i(TAG, "Cannot show Keyguard on null display");
101 return false;
102 }
103 if (display.getDisplayId() == DEFAULT_DISPLAY) {
104 if (DEBUG) Log.i(TAG, "Do not show KeyguardPresentation on the default display");
105 return false;
106 }
107 display.getDisplayInfo(mTmpDisplayInfo);
108 if ((mTmpDisplayInfo.flags & Display.FLAG_PRIVATE) != 0) {
109 if (DEBUG) Log.i(TAG, "Do not show KeyguardPresentation on a private display");
110 return false;
111 }
112 return true;
113 }
wilsonshihe7903ea2018-09-26 16:17:59 +0800114 /**
115 * @param display The display to show the presentation on.
116 * @return {@code true} if a presentation was added.
117 * {@code false} if the presentation cannot be added on that display or the presentation
118 * was already there.
119 */
120 private boolean showPresentation(Display display) {
wilsonshihb5d1ab92018-12-06 12:52:31 +0800121 if (!isKeyguardShowable(display)) return false;
wilsonshihe7903ea2018-09-26 16:17:59 +0800122 if (DEBUG) Log.i(TAG, "Keyguard enabled on display: " + display);
123 final int displayId = display.getDisplayId();
124 Presentation presentation = mPresentations.get(displayId);
125 if (presentation == null) {
Robert Snoebergerbe35b762019-03-15 14:33:02 -0400126 presentation = new KeyguardPresentation(mContext, display, mInjectableInflater);
wilsonshihe7903ea2018-09-26 16:17:59 +0800127 presentation.setOnDismissListener(dialog -> {
128 if (null != mPresentations.get(displayId)) {
129 mPresentations.remove(displayId);
130 }
131 });
132 try {
133 presentation.show();
134 } catch (WindowManager.InvalidDisplayException ex) {
135 Log.w(TAG, "Invalid display:", ex);
136 presentation = null;
137 }
138 if (presentation != null) {
139 mPresentations.append(displayId, presentation);
140 return true;
141 }
142 }
143 return false;
144 }
145
146 /**
147 * @param displayId The id of the display to hide the presentation off.
wilsonshihe7903ea2018-09-26 16:17:59 +0800148 */
wilsonshih177261f2019-02-22 12:02:18 +0800149 private void hidePresentation(int displayId) {
wilsonshihe7903ea2018-09-26 16:17:59 +0800150 final Presentation presentation = mPresentations.get(displayId);
151 if (presentation != null) {
152 presentation.dismiss();
153 mPresentations.remove(displayId);
wilsonshihe7903ea2018-09-26 16:17:59 +0800154 }
Jim Miller31921482013-11-06 20:43:55 -0800155 }
156
Jorim Jaggi5cf17872014-03-26 18:31:48 +0100157 public void show() {
Jim Miller31921482013-11-06 20:43:55 -0800158 if (!mShowing) {
wilsonshihe7903ea2018-09-26 16:17:59 +0800159 if (DEBUG) Log.v(TAG, "show");
Jim Miller31921482013-11-06 20:43:55 -0800160 mMediaRouter.addCallback(MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY,
161 mMediaRouterCallback, MediaRouter.CALLBACK_FLAG_PASSIVE_DISCOVERY);
wilsonshih177261f2019-02-22 12:02:18 +0800162 updateDisplays(true /* showing */);
Jim Miller31921482013-11-06 20:43:55 -0800163 }
164 mShowing = true;
165 }
166
Jorim Jaggi5cf17872014-03-26 18:31:48 +0100167 public void hide() {
Jim Miller31921482013-11-06 20:43:55 -0800168 if (mShowing) {
wilsonshihe7903ea2018-09-26 16:17:59 +0800169 if (DEBUG) Log.v(TAG, "hide");
Jim Miller31921482013-11-06 20:43:55 -0800170 mMediaRouter.removeCallback(mMediaRouterCallback);
wilsonshih177261f2019-02-22 12:02:18 +0800171 updateDisplays(false /* showing */);
Jim Miller31921482013-11-06 20:43:55 -0800172 }
173 mShowing = false;
174 }
175
176 private final MediaRouter.SimpleCallback mMediaRouterCallback =
177 new MediaRouter.SimpleCallback() {
178 @Override
179 public void onRouteSelected(MediaRouter router, int type, RouteInfo info) {
wilsonshihe7903ea2018-09-26 16:17:59 +0800180 if (DEBUG) Log.d(TAG, "onRouteSelected: type=" + type + ", info=" + info);
wilsonshih177261f2019-02-22 12:02:18 +0800181 updateDisplays(mShowing);
Jim Miller31921482013-11-06 20:43:55 -0800182 }
183
184 @Override
185 public void onRouteUnselected(MediaRouter router, int type, RouteInfo info) {
wilsonshihe7903ea2018-09-26 16:17:59 +0800186 if (DEBUG) Log.d(TAG, "onRouteUnselected: type=" + type + ", info=" + info);
wilsonshih177261f2019-02-22 12:02:18 +0800187 updateDisplays(mShowing);
Jim Miller31921482013-11-06 20:43:55 -0800188 }
189
190 @Override
191 public void onRoutePresentationDisplayChanged(MediaRouter router, RouteInfo info) {
wilsonshihe7903ea2018-09-26 16:17:59 +0800192 if (DEBUG) Log.d(TAG, "onRoutePresentationDisplayChanged: info=" + info);
wilsonshih177261f2019-02-22 12:02:18 +0800193 updateDisplays(mShowing);
Jim Miller31921482013-11-06 20:43:55 -0800194 }
195 };
196
wilsonshihe7903ea2018-09-26 16:17:59 +0800197 protected boolean updateDisplays(boolean showing) {
198 boolean changed = false;
Jim Miller31921482013-11-06 20:43:55 -0800199 if (showing) {
wilsonshihe7903ea2018-09-26 16:17:59 +0800200 final Display[] displays = mDisplayService.getDisplays();
201 for (Display display : displays) {
Charles Chen64172bb2019-04-22 17:30:29 +0800202 int displayId = display.getDisplayId();
203 updateNavigationBarVisibility(displayId, false /* navBarVisible */);
wilsonshihe7903ea2018-09-26 16:17:59 +0800204 changed |= showPresentation(display);
Jim Miller31921482013-11-06 20:43:55 -0800205 }
206 } else {
wilsonshihe7903ea2018-09-26 16:17:59 +0800207 changed = mPresentations.size() > 0;
208 for (int i = mPresentations.size() - 1; i >= 0; i--) {
Charles Chen64172bb2019-04-22 17:30:29 +0800209 int displayId = mPresentations.keyAt(i);
210 updateNavigationBarVisibility(displayId, true /* navBarVisible */);
wilsonshihe7903ea2018-09-26 16:17:59 +0800211 mPresentations.valueAt(i).dismiss();
Jim Miller31921482013-11-06 20:43:55 -0800212 }
wilsonshihe7903ea2018-09-26 16:17:59 +0800213 mPresentations.clear();
Jim Miller31921482013-11-06 20:43:55 -0800214 }
wilsonshihe7903ea2018-09-26 16:17:59 +0800215 return changed;
Jim Miller31921482013-11-06 20:43:55 -0800216 }
217
Charles Chen64172bb2019-04-22 17:30:29 +0800218 // TODO(b/127878649): this logic is from
219 // {@link StatusBarKeyguardViewManager#updateNavigationBarVisibility}. Try to revisit a long
220 // term solution in R.
221 private void updateNavigationBarVisibility(int displayId, boolean navBarVisible) {
222 // Leave this task to {@link StatusBarKeyguardViewManager}
223 if (displayId == DEFAULT_DISPLAY) return;
224
225 NavigationBarView navBarView = mNavBarController.getNavigationBarView(displayId);
226 // We may not have nav bar on a display.
227 if (navBarView == null) return;
228
229 if (navBarVisible) {
230 navBarView.getRootView().setVisibility(View.VISIBLE);
231 } else {
232 navBarView.getRootView().setVisibility(View.GONE);
233 }
234
235 }
236
Jim Miller31921482013-11-06 20:43:55 -0800237 private final static class KeyguardPresentation extends Presentation {
238 private static final int VIDEO_SAFE_REGION = 80; // Percentage of display width & height
239 private static final int MOVE_CLOCK_TIMEOUT = 10000; // 10s
Robert Snoebergerbe35b762019-03-15 14:33:02 -0400240 private final InjectionInflationController mInjectableInflater;
Jim Miller31921482013-11-06 20:43:55 -0800241 private View mClock;
242 private int mUsableWidth;
243 private int mUsableHeight;
244 private int mMarginTop;
245 private int mMarginLeft;
246 Runnable mMoveTextRunnable = new Runnable() {
247 @Override
248 public void run() {
249 int x = mMarginLeft + (int) (Math.random() * (mUsableWidth - mClock.getWidth()));
250 int y = mMarginTop + (int) (Math.random() * (mUsableHeight - mClock.getHeight()));
251 mClock.setTranslationX(x);
252 mClock.setTranslationY(y);
253 mClock.postDelayed(mMoveTextRunnable, MOVE_CLOCK_TIMEOUT);
254 }
255 };
256
Robert Snoebergerbe35b762019-03-15 14:33:02 -0400257 KeyguardPresentation(Context context, Display display,
258 InjectionInflationController injectionInflater) {
wilsonshihe7903ea2018-09-26 16:17:59 +0800259 super(context, display, R.style.keyguard_presentation_theme);
Robert Snoebergerbe35b762019-03-15 14:33:02 -0400260 mInjectableInflater = injectionInflater;
Jim Miller31921482013-11-06 20:43:55 -0800261 getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
wilsonshihe7903ea2018-09-26 16:17:59 +0800262 setCancelable(false);
Jim Miller31921482013-11-06 20:43:55 -0800263 }
264
Jim Millerc90d6452015-07-06 18:17:34 -0700265 @Override
Jim Miller31921482013-11-06 20:43:55 -0800266 public void onDetachedFromWindow() {
267 mClock.removeCallbacks(mMoveTextRunnable);
268 }
269
270 @Override
271 protected void onCreate(Bundle savedInstanceState) {
272 super.onCreate(savedInstanceState);
273
274 Point p = new Point();
275 getDisplay().getSize(p);
276 mUsableWidth = VIDEO_SAFE_REGION * p.x/100;
277 mUsableHeight = VIDEO_SAFE_REGION * p.y/100;
278 mMarginLeft = (100 - VIDEO_SAFE_REGION) * p.x / 200;
279 mMarginTop = (100 - VIDEO_SAFE_REGION) * p.y / 200;
280
Robert Snoebergerbe35b762019-03-15 14:33:02 -0400281 LayoutInflater inflater = mInjectableInflater.injectable(
282 LayoutInflater.from(getContext()));
283 setContentView(inflater.inflate(R.layout.keyguard_presentation, null));
Charles Chen64172bb2019-04-22 17:30:29 +0800284
285 // Logic to make the lock screen fullscreen
286 getWindow().getDecorView().setSystemUiVisibility(
287 View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
288 | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
289 | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
290 getWindow().setNavigationBarContrastEnforced(false);
291 getWindow().setNavigationBarColor(Color.TRANSPARENT);
292
Jim Miller31921482013-11-06 20:43:55 -0800293 mClock = findViewById(R.id.clock);
294
295 // Avoid screen burn in
296 mClock.post(mMoveTextRunnable);
297 }
298 }
299}