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 */
16package com.android.keyguard;
17
18import android.app.Presentation;
19import android.content.Context;
20import android.content.DialogInterface;
21import android.content.DialogInterface.OnDismissListener;
22import android.graphics.Point;
23import android.media.MediaRouter;
24import android.media.MediaRouter.RouteInfo;
25import android.os.Bundle;
26import android.util.Slog;
27import android.view.Display;
28import android.view.View;
29import android.view.WindowManager;
30
31public class KeyguardDisplayManager {
32    protected static final String TAG = "KeyguardDisplayManager";
33    private static boolean DEBUG = KeyguardConstants.DEBUG;
34    Presentation mPresentation;
35    private MediaRouter mMediaRouter;
36    private Context mContext;
37    private boolean mShowing;
38
39    public KeyguardDisplayManager(Context context) {
40        mContext = context;
41        mMediaRouter = (MediaRouter) mContext.getSystemService(Context.MEDIA_ROUTER_SERVICE);
42    }
43
44    public 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    public 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