blob: 9380eb4b03f07cf6fd81838d26c979fc3cdf80d4 [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
Lucas Dupin7a271052019-05-27 22:33:32 -070036import com.android.internal.annotations.VisibleForTesting;
Charles Chen64172bb2019-04-22 17:30:29 +080037import com.android.systemui.Dependency;
Sunny Goyal87fccf02019-08-13 17:39:10 -070038import com.android.systemui.R;
Charles Chen64172bb2019-04-22 17:30:29 +080039import com.android.systemui.statusbar.NavigationBarController;
40import com.android.systemui.statusbar.phone.NavigationBarView;
Robert Snoebergerbe35b762019-03-15 14:33:02 -040041import com.android.systemui.util.InjectionInflationController;
42
Jim Miller31921482013-11-06 20:43:55 -080043public class KeyguardDisplayManager {
44 protected static final String TAG = "KeyguardDisplayManager";
Jorim Jaggi5cf17872014-03-26 18:31:48 +010045 private static boolean DEBUG = KeyguardConstants.DEBUG;
David Stevens53a39ea2017-08-23 18:41:49 -070046
David Stevens53a39ea2017-08-23 18:41:49 -070047 private final MediaRouter mMediaRouter;
wilsonshihe7903ea2018-09-26 16:17:59 +080048 private final DisplayManager mDisplayService;
Robert Snoebergerbe35b762019-03-15 14:33:02 -040049 private final InjectionInflationController mInjectableInflater;
David Stevens53a39ea2017-08-23 18:41:49 -070050 private final Context mContext;
51
Jim Miller31921482013-11-06 20:43:55 -080052 private boolean mShowing;
wilsonshihb5d1ab92018-12-06 12:52:31 +080053 private final DisplayInfo mTmpDisplayInfo = new DisplayInfo();
Jim Miller31921482013-11-06 20:43:55 -080054
wilsonshihe7903ea2018-09-26 16:17:59 +080055 private final SparseArray<Presentation> mPresentations = new SparseArray<>();
56
Charles Chen64172bb2019-04-22 17:30:29 +080057 private final NavigationBarController mNavBarController =
58 Dependency.get(NavigationBarController.class);
59
wilsonshihe7903ea2018-09-26 16:17:59 +080060 private final DisplayManager.DisplayListener mDisplayListener =
61 new DisplayManager.DisplayListener() {
62
63 @Override
64 public void onDisplayAdded(int displayId) {
65 final Display display = mDisplayService.getDisplay(displayId);
66 if (mShowing) {
Charles Chen64172bb2019-04-22 17:30:29 +080067 updateNavigationBarVisibility(displayId, false /* navBarVisible */);
wilsonshih177261f2019-02-22 12:02:18 +080068 showPresentation(display);
wilsonshihe7903ea2018-09-26 16:17:59 +080069 }
70 }
71
72 @Override
73 public void onDisplayChanged(int displayId) {
74 if (displayId == DEFAULT_DISPLAY) return;
75 final Display display = mDisplayService.getDisplay(displayId);
76 if (display != null && mShowing) {
77 final Presentation presentation = mPresentations.get(displayId);
78 if (presentation != null && !presentation.getDisplay().equals(display)) {
79 hidePresentation(displayId);
80 showPresentation(display);
81 }
82 }
83 }
84
85 @Override
86 public void onDisplayRemoved(int displayId) {
wilsonshih177261f2019-02-22 12:02:18 +080087 hidePresentation(displayId);
wilsonshihe7903ea2018-09-26 16:17:59 +080088 }
89 };
90
Robert Snoebergerbe35b762019-03-15 14:33:02 -040091 public KeyguardDisplayManager(Context context,
92 InjectionInflationController injectableInflater) {
Jim Miller31921482013-11-06 20:43:55 -080093 mContext = context;
Robert Snoebergerbe35b762019-03-15 14:33:02 -040094 mInjectableInflater = injectableInflater;
wilsonshihe7903ea2018-09-26 16:17:59 +080095 mMediaRouter = mContext.getSystemService(MediaRouter.class);
96 mDisplayService = mContext.getSystemService(DisplayManager.class);
97 mDisplayService.registerDisplayListener(mDisplayListener, null /* handler */);
98 }
99
wilsonshihb5d1ab92018-12-06 12:52:31 +0800100 private boolean isKeyguardShowable(Display display) {
101 if (display == null) {
102 if (DEBUG) Log.i(TAG, "Cannot show Keyguard on null display");
103 return false;
104 }
105 if (display.getDisplayId() == DEFAULT_DISPLAY) {
106 if (DEBUG) Log.i(TAG, "Do not show KeyguardPresentation on the default display");
107 return false;
108 }
109 display.getDisplayInfo(mTmpDisplayInfo);
110 if ((mTmpDisplayInfo.flags & Display.FLAG_PRIVATE) != 0) {
111 if (DEBUG) Log.i(TAG, "Do not show KeyguardPresentation on a private display");
112 return false;
113 }
114 return true;
115 }
wilsonshihe7903ea2018-09-26 16:17:59 +0800116 /**
117 * @param display The display to show the presentation on.
118 * @return {@code true} if a presentation was added.
119 * {@code false} if the presentation cannot be added on that display or the presentation
120 * was already there.
121 */
122 private boolean showPresentation(Display display) {
wilsonshihb5d1ab92018-12-06 12:52:31 +0800123 if (!isKeyguardShowable(display)) return false;
wilsonshihe7903ea2018-09-26 16:17:59 +0800124 if (DEBUG) Log.i(TAG, "Keyguard enabled on display: " + display);
125 final int displayId = display.getDisplayId();
126 Presentation presentation = mPresentations.get(displayId);
127 if (presentation == null) {
Robert Snoebergerbe35b762019-03-15 14:33:02 -0400128 presentation = new KeyguardPresentation(mContext, display, mInjectableInflater);
wilsonshihe7903ea2018-09-26 16:17:59 +0800129 presentation.setOnDismissListener(dialog -> {
130 if (null != mPresentations.get(displayId)) {
131 mPresentations.remove(displayId);
132 }
133 });
134 try {
135 presentation.show();
136 } catch (WindowManager.InvalidDisplayException ex) {
137 Log.w(TAG, "Invalid display:", ex);
138 presentation = null;
139 }
140 if (presentation != null) {
141 mPresentations.append(displayId, presentation);
142 return true;
143 }
144 }
145 return false;
146 }
147
148 /**
149 * @param displayId The id of the display to hide the presentation off.
wilsonshihe7903ea2018-09-26 16:17:59 +0800150 */
wilsonshih177261f2019-02-22 12:02:18 +0800151 private void hidePresentation(int displayId) {
wilsonshihe7903ea2018-09-26 16:17:59 +0800152 final Presentation presentation = mPresentations.get(displayId);
153 if (presentation != null) {
154 presentation.dismiss();
155 mPresentations.remove(displayId);
wilsonshihe7903ea2018-09-26 16:17:59 +0800156 }
Jim Miller31921482013-11-06 20:43:55 -0800157 }
158
Jorim Jaggi5cf17872014-03-26 18:31:48 +0100159 public void show() {
Jim Miller31921482013-11-06 20:43:55 -0800160 if (!mShowing) {
wilsonshihe7903ea2018-09-26 16:17:59 +0800161 if (DEBUG) Log.v(TAG, "show");
Jim Miller31921482013-11-06 20:43:55 -0800162 mMediaRouter.addCallback(MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY,
163 mMediaRouterCallback, MediaRouter.CALLBACK_FLAG_PASSIVE_DISCOVERY);
wilsonshih177261f2019-02-22 12:02:18 +0800164 updateDisplays(true /* showing */);
Jim Miller31921482013-11-06 20:43:55 -0800165 }
166 mShowing = true;
167 }
168
Jorim Jaggi5cf17872014-03-26 18:31:48 +0100169 public void hide() {
Jim Miller31921482013-11-06 20:43:55 -0800170 if (mShowing) {
wilsonshihe7903ea2018-09-26 16:17:59 +0800171 if (DEBUG) Log.v(TAG, "hide");
Jim Miller31921482013-11-06 20:43:55 -0800172 mMediaRouter.removeCallback(mMediaRouterCallback);
wilsonshih177261f2019-02-22 12:02:18 +0800173 updateDisplays(false /* showing */);
Jim Miller31921482013-11-06 20:43:55 -0800174 }
175 mShowing = false;
176 }
177
178 private final MediaRouter.SimpleCallback mMediaRouterCallback =
179 new MediaRouter.SimpleCallback() {
180 @Override
181 public void onRouteSelected(MediaRouter router, int type, RouteInfo info) {
wilsonshihe7903ea2018-09-26 16:17:59 +0800182 if (DEBUG) Log.d(TAG, "onRouteSelected: type=" + type + ", info=" + info);
wilsonshih177261f2019-02-22 12:02:18 +0800183 updateDisplays(mShowing);
Jim Miller31921482013-11-06 20:43:55 -0800184 }
185
186 @Override
187 public void onRouteUnselected(MediaRouter router, int type, RouteInfo info) {
wilsonshihe7903ea2018-09-26 16:17:59 +0800188 if (DEBUG) Log.d(TAG, "onRouteUnselected: type=" + type + ", info=" + info);
wilsonshih177261f2019-02-22 12:02:18 +0800189 updateDisplays(mShowing);
Jim Miller31921482013-11-06 20:43:55 -0800190 }
191
192 @Override
193 public void onRoutePresentationDisplayChanged(MediaRouter router, RouteInfo info) {
wilsonshihe7903ea2018-09-26 16:17:59 +0800194 if (DEBUG) Log.d(TAG, "onRoutePresentationDisplayChanged: info=" + info);
wilsonshih177261f2019-02-22 12:02:18 +0800195 updateDisplays(mShowing);
Jim Miller31921482013-11-06 20:43:55 -0800196 }
197 };
198
wilsonshihe7903ea2018-09-26 16:17:59 +0800199 protected boolean updateDisplays(boolean showing) {
200 boolean changed = false;
Jim Miller31921482013-11-06 20:43:55 -0800201 if (showing) {
wilsonshihe7903ea2018-09-26 16:17:59 +0800202 final Display[] displays = mDisplayService.getDisplays();
203 for (Display display : displays) {
Charles Chen64172bb2019-04-22 17:30:29 +0800204 int displayId = display.getDisplayId();
205 updateNavigationBarVisibility(displayId, false /* navBarVisible */);
wilsonshihe7903ea2018-09-26 16:17:59 +0800206 changed |= showPresentation(display);
Jim Miller31921482013-11-06 20:43:55 -0800207 }
208 } else {
wilsonshihe7903ea2018-09-26 16:17:59 +0800209 changed = mPresentations.size() > 0;
210 for (int i = mPresentations.size() - 1; i >= 0; i--) {
Charles Chen64172bb2019-04-22 17:30:29 +0800211 int displayId = mPresentations.keyAt(i);
212 updateNavigationBarVisibility(displayId, true /* navBarVisible */);
wilsonshihe7903ea2018-09-26 16:17:59 +0800213 mPresentations.valueAt(i).dismiss();
Jim Miller31921482013-11-06 20:43:55 -0800214 }
wilsonshihe7903ea2018-09-26 16:17:59 +0800215 mPresentations.clear();
Jim Miller31921482013-11-06 20:43:55 -0800216 }
wilsonshihe7903ea2018-09-26 16:17:59 +0800217 return changed;
Jim Miller31921482013-11-06 20:43:55 -0800218 }
219
Charles Chen64172bb2019-04-22 17:30:29 +0800220 // TODO(b/127878649): this logic is from
221 // {@link StatusBarKeyguardViewManager#updateNavigationBarVisibility}. Try to revisit a long
222 // term solution in R.
223 private void updateNavigationBarVisibility(int displayId, boolean navBarVisible) {
224 // Leave this task to {@link StatusBarKeyguardViewManager}
225 if (displayId == DEFAULT_DISPLAY) return;
226
227 NavigationBarView navBarView = mNavBarController.getNavigationBarView(displayId);
228 // We may not have nav bar on a display.
229 if (navBarView == null) return;
230
231 if (navBarVisible) {
232 navBarView.getRootView().setVisibility(View.VISIBLE);
233 } else {
234 navBarView.getRootView().setVisibility(View.GONE);
235 }
236
237 }
238
Lucas Dupin7a271052019-05-27 22:33:32 -0700239 @VisibleForTesting
240 static final class KeyguardPresentation extends Presentation {
Jim Miller31921482013-11-06 20:43:55 -0800241 private static final int VIDEO_SAFE_REGION = 80; // Percentage of display width & height
242 private static final int MOVE_CLOCK_TIMEOUT = 10000; // 10s
Robert Snoebergerbe35b762019-03-15 14:33:02 -0400243 private final InjectionInflationController mInjectableInflater;
Jim Miller31921482013-11-06 20:43:55 -0800244 private View mClock;
245 private int mUsableWidth;
246 private int mUsableHeight;
247 private int mMarginTop;
248 private int mMarginLeft;
249 Runnable mMoveTextRunnable = new Runnable() {
250 @Override
251 public void run() {
252 int x = mMarginLeft + (int) (Math.random() * (mUsableWidth - mClock.getWidth()));
253 int y = mMarginTop + (int) (Math.random() * (mUsableHeight - mClock.getHeight()));
254 mClock.setTranslationX(x);
255 mClock.setTranslationY(y);
256 mClock.postDelayed(mMoveTextRunnable, MOVE_CLOCK_TIMEOUT);
257 }
258 };
259
Robert Snoebergerbe35b762019-03-15 14:33:02 -0400260 KeyguardPresentation(Context context, Display display,
261 InjectionInflationController injectionInflater) {
Lucas Dupin7a271052019-05-27 22:33:32 -0700262 super(context, display, R.style.Theme_SystemUI_KeyguardPresentation);
Robert Snoebergerbe35b762019-03-15 14:33:02 -0400263 mInjectableInflater = injectionInflater;
Jim Miller31921482013-11-06 20:43:55 -0800264 getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
wilsonshihe7903ea2018-09-26 16:17:59 +0800265 setCancelable(false);
Jim Miller31921482013-11-06 20:43:55 -0800266 }
267
Jim Millerc90d6452015-07-06 18:17:34 -0700268 @Override
Jim Miller31921482013-11-06 20:43:55 -0800269 public void onDetachedFromWindow() {
270 mClock.removeCallbacks(mMoveTextRunnable);
271 }
272
273 @Override
274 protected void onCreate(Bundle savedInstanceState) {
275 super.onCreate(savedInstanceState);
276
277 Point p = new Point();
278 getDisplay().getSize(p);
279 mUsableWidth = VIDEO_SAFE_REGION * p.x/100;
280 mUsableHeight = VIDEO_SAFE_REGION * p.y/100;
281 mMarginLeft = (100 - VIDEO_SAFE_REGION) * p.x / 200;
282 mMarginTop = (100 - VIDEO_SAFE_REGION) * p.y / 200;
283
Robert Snoebergerbe35b762019-03-15 14:33:02 -0400284 LayoutInflater inflater = mInjectableInflater.injectable(
285 LayoutInflater.from(getContext()));
286 setContentView(inflater.inflate(R.layout.keyguard_presentation, null));
Charles Chen64172bb2019-04-22 17:30:29 +0800287
288 // Logic to make the lock screen fullscreen
289 getWindow().getDecorView().setSystemUiVisibility(
290 View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
291 | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
292 | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
293 getWindow().setNavigationBarContrastEnforced(false);
294 getWindow().setNavigationBarColor(Color.TRANSPARENT);
295
Jim Miller31921482013-11-06 20:43:55 -0800296 mClock = findViewById(R.id.clock);
297
298 // Avoid screen burn in
299 mClock.post(mMoveTextRunnable);
300 }
301 }
302}