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