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