• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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  */
16 package com.android.keyguard;
17 
18 import static android.view.Display.INVALID_DISPLAY;
19 
20 import android.app.Presentation;
21 import android.content.Context;
22 import android.content.DialogInterface;
23 import android.content.DialogInterface.OnDismissListener;
24 import android.graphics.Point;
25 import android.media.MediaRouter;
26 import android.media.MediaRouter.RouteInfo;
27 import android.os.Bundle;
28 import android.util.Slog;
29 import android.view.Display;
30 import android.view.View;
31 import android.view.WindowManager;
32 
33 // TODO(multi-display): Support multiple external displays
34 public class KeyguardDisplayManager {
35     protected static final String TAG = "KeyguardDisplayManager";
36     private static boolean DEBUG = KeyguardConstants.DEBUG;
37 
38     private final ViewMediatorCallback mCallback;
39     private final MediaRouter mMediaRouter;
40     private final Context mContext;
41 
42     Presentation mPresentation;
43     private boolean mShowing;
44 
KeyguardDisplayManager(Context context, ViewMediatorCallback callback)45     public KeyguardDisplayManager(Context context, ViewMediatorCallback callback) {
46         mContext = context;
47         mCallback = callback;
48         mMediaRouter = (MediaRouter) mContext.getSystemService(Context.MEDIA_ROUTER_SERVICE);
49     }
50 
show()51     public void show() {
52         if (!mShowing) {
53             if (DEBUG) Slog.v(TAG, "show");
54             mMediaRouter.addCallback(MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY,
55                     mMediaRouterCallback, MediaRouter.CALLBACK_FLAG_PASSIVE_DISCOVERY);
56             updateDisplays(true);
57         }
58         mShowing = true;
59     }
60 
hide()61     public void hide() {
62         if (mShowing) {
63             if (DEBUG) Slog.v(TAG, "hide");
64             mMediaRouter.removeCallback(mMediaRouterCallback);
65             updateDisplays(false);
66         }
67         mShowing = false;
68     }
69 
70     private final MediaRouter.SimpleCallback mMediaRouterCallback =
71             new MediaRouter.SimpleCallback() {
72         @Override
73         public void onRouteSelected(MediaRouter router, int type, RouteInfo info) {
74             if (DEBUG) Slog.d(TAG, "onRouteSelected: type=" + type + ", info=" + info);
75             updateDisplays(mShowing);
76         }
77 
78         @Override
79         public void onRouteUnselected(MediaRouter router, int type, RouteInfo info) {
80             if (DEBUG) Slog.d(TAG, "onRouteUnselected: type=" + type + ", info=" + info);
81             updateDisplays(mShowing);
82         }
83 
84         @Override
85         public void onRoutePresentationDisplayChanged(MediaRouter router, RouteInfo info) {
86             if (DEBUG) Slog.d(TAG, "onRoutePresentationDisplayChanged: info=" + info);
87             updateDisplays(mShowing);
88         }
89     };
90 
91     private OnDismissListener mOnDismissListener = new OnDismissListener() {
92 
93         @Override
94         public void onDismiss(DialogInterface dialog) {
95             mPresentation = null;
96         }
97     };
98 
updateDisplays(boolean showing)99     protected void updateDisplays(boolean showing) {
100         Presentation originalPresentation = mPresentation;
101         if (showing) {
102             MediaRouter.RouteInfo route = mMediaRouter.getSelectedRoute(
103                     MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY);
104             boolean useDisplay = route != null
105                     && route.getPlaybackType() == MediaRouter.RouteInfo.PLAYBACK_TYPE_REMOTE;
106             Display presentationDisplay = useDisplay ? route.getPresentationDisplay() : null;
107 
108             if (mPresentation != null && mPresentation.getDisplay() != presentationDisplay) {
109                 if (DEBUG) Slog.v(TAG, "Display gone: " + mPresentation.getDisplay());
110                 mPresentation.dismiss();
111                 mPresentation = null;
112             }
113 
114             if (mPresentation == null && presentationDisplay != null) {
115                 if (DEBUG) Slog.i(TAG, "Keyguard enabled on display: " + presentationDisplay);
116                 mPresentation = new KeyguardPresentation(mContext, presentationDisplay,
117                         R.style.keyguard_presentation_theme);
118                 mPresentation.setOnDismissListener(mOnDismissListener);
119                 try {
120                     mPresentation.show();
121                 } catch (WindowManager.InvalidDisplayException ex) {
122                     Slog.w(TAG, "Invalid display:", ex);
123                     mPresentation = null;
124                 }
125             }
126         } else {
127             if (mPresentation != null) {
128                 mPresentation.dismiss();
129                 mPresentation = null;
130             }
131         }
132 
133         // mPresentation is only updated when the display changes
134         if (mPresentation != originalPresentation) {
135             final int displayId = mPresentation != null
136                     ? mPresentation.getDisplay().getDisplayId() : INVALID_DISPLAY;
137             mCallback.onSecondaryDisplayShowingChanged(displayId);
138         }
139     }
140 
141     private final static class KeyguardPresentation extends Presentation {
142         private static final int VIDEO_SAFE_REGION = 80; // Percentage of display width & height
143         private static final int MOVE_CLOCK_TIMEOUT = 10000; // 10s
144         private View mClock;
145         private int mUsableWidth;
146         private int mUsableHeight;
147         private int mMarginTop;
148         private int mMarginLeft;
149         Runnable mMoveTextRunnable = new Runnable() {
150             @Override
151             public void run() {
152                 int x = mMarginLeft + (int) (Math.random() * (mUsableWidth - mClock.getWidth()));
153                 int y = mMarginTop + (int) (Math.random() * (mUsableHeight - mClock.getHeight()));
154                 mClock.setTranslationX(x);
155                 mClock.setTranslationY(y);
156                 mClock.postDelayed(mMoveTextRunnable, MOVE_CLOCK_TIMEOUT);
157             }
158         };
159 
KeyguardPresentation(Context context, Display display, int theme)160         public KeyguardPresentation(Context context, Display display, int theme) {
161             super(context, display, theme);
162             getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
163         }
164 
165         @Override
onDetachedFromWindow()166         public void onDetachedFromWindow() {
167             mClock.removeCallbacks(mMoveTextRunnable);
168         }
169 
170         @Override
onCreate(Bundle savedInstanceState)171         protected void onCreate(Bundle savedInstanceState) {
172             super.onCreate(savedInstanceState);
173 
174             Point p = new Point();
175             getDisplay().getSize(p);
176             mUsableWidth = VIDEO_SAFE_REGION * p.x/100;
177             mUsableHeight = VIDEO_SAFE_REGION * p.y/100;
178             mMarginLeft = (100 - VIDEO_SAFE_REGION) * p.x / 200;
179             mMarginTop = (100 - VIDEO_SAFE_REGION) * p.y / 200;
180 
181             setContentView(R.layout.keyguard_presentation);
182             mClock = findViewById(R.id.clock);
183 
184             // Avoid screen burn in
185             mClock.post(mMoveTextRunnable);
186         }
187     }
188 }
189