186b6357e5eb91950eac7de7ffe29e5a4ad32903bJohn Spurlock/*
286b6357e5eb91950eac7de7ffe29e5a4ad32903bJohn Spurlock * Copyright (C) 2012 The Android Open Source Project
386b6357e5eb91950eac7de7ffe29e5a4ad32903bJohn Spurlock *
486b6357e5eb91950eac7de7ffe29e5a4ad32903bJohn Spurlock * Licensed under the Apache License, Version 2.0 (the "License");
586b6357e5eb91950eac7de7ffe29e5a4ad32903bJohn Spurlock * you may not use this file except in compliance with the License.
686b6357e5eb91950eac7de7ffe29e5a4ad32903bJohn Spurlock * You may obtain a copy of the License at
786b6357e5eb91950eac7de7ffe29e5a4ad32903bJohn Spurlock *
886b6357e5eb91950eac7de7ffe29e5a4ad32903bJohn Spurlock *      http://www.apache.org/licenses/LICENSE-2.0
986b6357e5eb91950eac7de7ffe29e5a4ad32903bJohn Spurlock *
1086b6357e5eb91950eac7de7ffe29e5a4ad32903bJohn Spurlock * Unless required by applicable law or agreed to in writing, software
1186b6357e5eb91950eac7de7ffe29e5a4ad32903bJohn Spurlock * distributed under the License is distributed on an "AS IS" BASIS,
1286b6357e5eb91950eac7de7ffe29e5a4ad32903bJohn Spurlock * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1386b6357e5eb91950eac7de7ffe29e5a4ad32903bJohn Spurlock * See the License for the specific language governing permissions and
1486b6357e5eb91950eac7de7ffe29e5a4ad32903bJohn Spurlock * limitations under the License.
1586b6357e5eb91950eac7de7ffe29e5a4ad32903bJohn Spurlock */
1686b6357e5eb91950eac7de7ffe29e5a4ad32903bJohn Spurlock
1786b6357e5eb91950eac7de7ffe29e5a4ad32903bJohn Spurlockpackage com.android.internal.policy.impl.keyguard;
1886b6357e5eb91950eac7de7ffe29e5a4ad32903bJohn Spurlock
1986b6357e5eb91950eac7de7ffe29e5a4ad32903bJohn Spurlockimport android.content.Context;
2086b6357e5eb91950eac7de7ffe29e5a4ad32903bJohn Spurlockimport android.content.pm.PackageManager.NameNotFoundException;
21dcc9681b0d4f52e1f441ef2abdda3eb949cc0c4bJohn Spurlockimport android.graphics.Bitmap;
22dcc9681b0d4f52e1f441ef2abdda3eb949cc0c4bJohn Spurlockimport android.graphics.Canvas;
2386b6357e5eb91950eac7de7ffe29e5a4ad32903bJohn Spurlockimport android.graphics.Color;
24737798271e6e5b9466acef26ead061ecf6d0f292John Spurlockimport android.graphics.Point;
2586b6357e5eb91950eac7de7ffe29e5a4ad32903bJohn Spurlockimport android.os.Handler;
2686b6357e5eb91950eac7de7ffe29e5a4ad32903bJohn Spurlockimport android.os.SystemClock;
2786b6357e5eb91950eac7de7ffe29e5a4ad32903bJohn Spurlockimport android.util.Log;
2886b6357e5eb91950eac7de7ffe29e5a4ad32903bJohn Spurlockimport android.view.LayoutInflater;
294b976ea1af04f8c340ef7e0d79f73d7cdb5eb72eJohn Spurlockimport android.view.MotionEvent;
3086b6357e5eb91950eac7de7ffe29e5a4ad32903bJohn Spurlockimport android.view.View;
31737798271e6e5b9466acef26ead061ecf6d0f292John Spurlockimport android.view.ViewGroup;
32e2ac5207f204ee26ba43c033d9ffb51f7daee2bdJohn Spurlockimport android.view.WindowManager;
33dcc9681b0d4f52e1f441ef2abdda3eb949cc0c4bJohn Spurlockimport android.widget.FrameLayout;
34dcc9681b0d4f52e1f441ef2abdda3eb949cc0c4bJohn Spurlockimport android.widget.ImageView;
35dcc9681b0d4f52e1f441ef2abdda3eb949cc0c4bJohn Spurlockimport android.widget.ImageView.ScaleType;
3686b6357e5eb91950eac7de7ffe29e5a4ad32903bJohn Spurlock
37c4842c11932ea4f60fe7ae09b0a59660207e1587Svetoslav Ganovimport com.android.internal.R;
38dcc9681b0d4f52e1f441ef2abdda3eb949cc0c4bJohn Spurlockimport com.android.internal.policy.impl.keyguard.KeyguardActivityLauncher.CameraWidgetInfo;
3986b6357e5eb91950eac7de7ffe29e5a4ad32903bJohn Spurlock
404b976ea1af04f8c340ef7e0d79f73d7cdb5eb72eJohn Spurlockpublic class CameraWidgetFrame extends KeyguardWidgetFrame implements View.OnClickListener {
4186b6357e5eb91950eac7de7ffe29e5a4ad32903bJohn Spurlock    private static final String TAG = CameraWidgetFrame.class.getSimpleName();
4286b6357e5eb91950eac7de7ffe29e5a4ad32903bJohn Spurlock    private static final boolean DEBUG = KeyguardHostView.DEBUG;
4357f928fc4afc02d2fe45523efea687eee7f86c02John Spurlock    private static final int WIDGET_ANIMATION_DURATION = 250; // ms
4457f928fc4afc02d2fe45523efea687eee7f86c02John Spurlock    private static final int WIDGET_WAIT_DURATION = 650; // ms
4557f928fc4afc02d2fe45523efea687eee7f86c02John Spurlock    private static final int RECOVERY_DELAY = 1000; // ms
4686b6357e5eb91950eac7de7ffe29e5a4ad32903bJohn Spurlock
4786b6357e5eb91950eac7de7ffe29e5a4ad32903bJohn Spurlock    interface Callbacks {
4886b6357e5eb91950eac7de7ffe29e5a4ad32903bJohn Spurlock        void onLaunchingCamera();
4957f928fc4afc02d2fe45523efea687eee7f86c02John Spurlock        void onCameraLaunchedSuccessfully();
5057f928fc4afc02d2fe45523efea687eee7f86c02John Spurlock        void onCameraLaunchedUnsuccessfully();
5186b6357e5eb91950eac7de7ffe29e5a4ad32903bJohn Spurlock    }
5286b6357e5eb91950eac7de7ffe29e5a4ad32903bJohn Spurlock
5386b6357e5eb91950eac7de7ffe29e5a4ad32903bJohn Spurlock    private final Handler mHandler = new Handler();
54dcc9681b0d4f52e1f441ef2abdda3eb949cc0c4bJohn Spurlock    private final KeyguardActivityLauncher mActivityLauncher;
5586b6357e5eb91950eac7de7ffe29e5a4ad32903bJohn Spurlock    private final Callbacks mCallbacks;
56e2ac5207f204ee26ba43c033d9ffb51f7daee2bdJohn Spurlock    private final WindowManager mWindowManager;
57737798271e6e5b9466acef26ead061ecf6d0f292John Spurlock    private final Point mRenderedSize = new Point();
58bb5c941149b66c0192736468bb60f47984dd5e1fJohn Spurlock    private final int[] mScreenLocation = new int[2];
5986b6357e5eb91950eac7de7ffe29e5a4ad32903bJohn Spurlock
60dcc9681b0d4f52e1f441ef2abdda3eb949cc0c4bJohn Spurlock    private View mWidgetView;
6186b6357e5eb91950eac7de7ffe29e5a4ad32903bJohn Spurlock    private long mLaunchCameraStart;
624b976ea1af04f8c340ef7e0d79f73d7cdb5eb72eJohn Spurlock    private boolean mActive;
634b976ea1af04f8c340ef7e0d79f73d7cdb5eb72eJohn Spurlock    private boolean mTransitioning;
6457f928fc4afc02d2fe45523efea687eee7f86c02John Spurlock    private boolean mRecovering;
654b976ea1af04f8c340ef7e0d79f73d7cdb5eb72eJohn Spurlock    private boolean mDown;
6686b6357e5eb91950eac7de7ffe29e5a4ad32903bJohn Spurlock
6757f928fc4afc02d2fe45523efea687eee7f86c02John Spurlock    private final Runnable mTransitionToCameraRunnable = new Runnable() {
6857f928fc4afc02d2fe45523efea687eee7f86c02John Spurlock        @Override
6957f928fc4afc02d2fe45523efea687eee7f86c02John Spurlock        public void run() {
7057f928fc4afc02d2fe45523efea687eee7f86c02John Spurlock            transitionToCamera();
7157f928fc4afc02d2fe45523efea687eee7f86c02John Spurlock        }};
7257f928fc4afc02d2fe45523efea687eee7f86c02John Spurlock
7357f928fc4afc02d2fe45523efea687eee7f86c02John Spurlock    private final Runnable mTransitionToCameraEndAction = new Runnable() {
7486b6357e5eb91950eac7de7ffe29e5a4ad32903bJohn Spurlock        @Override
7586b6357e5eb91950eac7de7ffe29e5a4ad32903bJohn Spurlock        public void run() {
76dbe24b7def8df3a539790827d3f395f4d933802bJohn Spurlock            if (!mTransitioning)
77dbe24b7def8df3a539790827d3f395f4d933802bJohn Spurlock                return;
7857f928fc4afc02d2fe45523efea687eee7f86c02John Spurlock            Handler worker =  getWorkerHandler() != null ? getWorkerHandler() : mHandler;
7947cde77bc7ac5c3a1e486691596a7534ad855ff2John Spurlock            mLaunchCameraStart = SystemClock.uptimeMillis();
80dbe24b7def8df3a539790827d3f395f4d933802bJohn Spurlock            if (DEBUG) Log.d(TAG, "Launching camera at " + mLaunchCameraStart);
8157f928fc4afc02d2fe45523efea687eee7f86c02John Spurlock            mActivityLauncher.launchCamera(worker, mSecureCameraActivityStartedRunnable);
8257f928fc4afc02d2fe45523efea687eee7f86c02John Spurlock        }};
8357f928fc4afc02d2fe45523efea687eee7f86c02John Spurlock
8457f928fc4afc02d2fe45523efea687eee7f86c02John Spurlock    private final Runnable mRecoverRunnable = new Runnable() {
8557f928fc4afc02d2fe45523efea687eee7f86c02John Spurlock        @Override
8657f928fc4afc02d2fe45523efea687eee7f86c02John Spurlock        public void run() {
8757f928fc4afc02d2fe45523efea687eee7f86c02John Spurlock            recover();
8857f928fc4afc02d2fe45523efea687eee7f86c02John Spurlock        }};
8957f928fc4afc02d2fe45523efea687eee7f86c02John Spurlock
9057f928fc4afc02d2fe45523efea687eee7f86c02John Spurlock    private final Runnable mRecoverEndAction = new Runnable() {
9157f928fc4afc02d2fe45523efea687eee7f86c02John Spurlock        @Override
9257f928fc4afc02d2fe45523efea687eee7f86c02John Spurlock        public void run() {
9357f928fc4afc02d2fe45523efea687eee7f86c02John Spurlock            if (!mRecovering)
9457f928fc4afc02d2fe45523efea687eee7f86c02John Spurlock                return;
9557f928fc4afc02d2fe45523efea687eee7f86c02John Spurlock            mCallbacks.onCameraLaunchedUnsuccessfully();
9657f928fc4afc02d2fe45523efea687eee7f86c02John Spurlock            reset();
97dcc9681b0d4f52e1f441ef2abdda3eb949cc0c4bJohn Spurlock        }};
98dcc9681b0d4f52e1f441ef2abdda3eb949cc0c4bJohn Spurlock
99dcc9681b0d4f52e1f441ef2abdda3eb949cc0c4bJohn Spurlock    private final Runnable mRenderRunnable = new Runnable() {
100dcc9681b0d4f52e1f441ef2abdda3eb949cc0c4bJohn Spurlock        @Override
101dcc9681b0d4f52e1f441ef2abdda3eb949cc0c4bJohn Spurlock        public void run() {
102dcc9681b0d4f52e1f441ef2abdda3eb949cc0c4bJohn Spurlock            render();
10386b6357e5eb91950eac7de7ffe29e5a4ad32903bJohn Spurlock        }};
10486b6357e5eb91950eac7de7ffe29e5a4ad32903bJohn Spurlock
10557f928fc4afc02d2fe45523efea687eee7f86c02John Spurlock    private final Runnable mSecureCameraActivityStartedRunnable = new Runnable() {
1064b976ea1af04f8c340ef7e0d79f73d7cdb5eb72eJohn Spurlock        @Override
1074b976ea1af04f8c340ef7e0d79f73d7cdb5eb72eJohn Spurlock        public void run() {
10857f928fc4afc02d2fe45523efea687eee7f86c02John Spurlock            onSecureCameraActivityStarted();
10957f928fc4afc02d2fe45523efea687eee7f86c02John Spurlock        }
11057f928fc4afc02d2fe45523efea687eee7f86c02John Spurlock    };
1114b976ea1af04f8c340ef7e0d79f73d7cdb5eb72eJohn Spurlock
1126275b3f1f3de7b0ca285e8f57a6d6014b0fa95b3John Spurlock    private final KeyguardUpdateMonitorCallback mCallback = new KeyguardUpdateMonitorCallback() {
1136275b3f1f3de7b0ca285e8f57a6d6014b0fa95b3John Spurlock        private boolean mShowing;
1146275b3f1f3de7b0ca285e8f57a6d6014b0fa95b3John Spurlock        void onKeyguardVisibilityChanged(boolean showing) {
1156275b3f1f3de7b0ca285e8f57a6d6014b0fa95b3John Spurlock            if (mShowing == showing)
1166275b3f1f3de7b0ca285e8f57a6d6014b0fa95b3John Spurlock                return;
1176275b3f1f3de7b0ca285e8f57a6d6014b0fa95b3John Spurlock            mShowing = showing;
1186275b3f1f3de7b0ca285e8f57a6d6014b0fa95b3John Spurlock            CameraWidgetFrame.this.onKeyguardVisibilityChanged(mShowing);
1196275b3f1f3de7b0ca285e8f57a6d6014b0fa95b3John Spurlock        };
1206275b3f1f3de7b0ca285e8f57a6d6014b0fa95b3John Spurlock    };
1216275b3f1f3de7b0ca285e8f57a6d6014b0fa95b3John Spurlock
122dcc9681b0d4f52e1f441ef2abdda3eb949cc0c4bJohn Spurlock    private CameraWidgetFrame(Context context, Callbacks callbacks,
123dcc9681b0d4f52e1f441ef2abdda3eb949cc0c4bJohn Spurlock            KeyguardActivityLauncher activityLauncher) {
12486b6357e5eb91950eac7de7ffe29e5a4ad32903bJohn Spurlock        super(context);
12586b6357e5eb91950eac7de7ffe29e5a4ad32903bJohn Spurlock        mCallbacks = callbacks;
126dcc9681b0d4f52e1f441ef2abdda3eb949cc0c4bJohn Spurlock        mActivityLauncher = activityLauncher;
127e2ac5207f204ee26ba43c033d9ffb51f7daee2bdJohn Spurlock        mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
1286275b3f1f3de7b0ca285e8f57a6d6014b0fa95b3John Spurlock        KeyguardUpdateMonitor.getInstance(context).registerCallback(mCallback);
1296275b3f1f3de7b0ca285e8f57a6d6014b0fa95b3John Spurlock        if (DEBUG) Log.d(TAG, "new CameraWidgetFrame instance " + instanceId());
130dcc9681b0d4f52e1f441ef2abdda3eb949cc0c4bJohn Spurlock    }
13186b6357e5eb91950eac7de7ffe29e5a4ad32903bJohn Spurlock
132dcc9681b0d4f52e1f441ef2abdda3eb949cc0c4bJohn Spurlock    public static CameraWidgetFrame create(Context context, Callbacks callbacks,
133dcc9681b0d4f52e1f441ef2abdda3eb949cc0c4bJohn Spurlock            KeyguardActivityLauncher launcher) {
134dcc9681b0d4f52e1f441ef2abdda3eb949cc0c4bJohn Spurlock        if (context == null || callbacks == null || launcher == null)
135dcc9681b0d4f52e1f441ef2abdda3eb949cc0c4bJohn Spurlock            return null;
136dcc9681b0d4f52e1f441ef2abdda3eb949cc0c4bJohn Spurlock
137dcc9681b0d4f52e1f441ef2abdda3eb949cc0c4bJohn Spurlock        CameraWidgetInfo widgetInfo = launcher.getCameraWidgetInfo();
138dcc9681b0d4f52e1f441ef2abdda3eb949cc0c4bJohn Spurlock        if (widgetInfo == null)
139dcc9681b0d4f52e1f441ef2abdda3eb949cc0c4bJohn Spurlock            return null;
140dcc9681b0d4f52e1f441ef2abdda3eb949cc0c4bJohn Spurlock        View widgetView = widgetInfo.layoutId > 0 ?
141dcc9681b0d4f52e1f441ef2abdda3eb949cc0c4bJohn Spurlock                inflateWidgetView(context, widgetInfo) :
142dcc9681b0d4f52e1f441ef2abdda3eb949cc0c4bJohn Spurlock                inflateGenericWidgetView(context);
143dcc9681b0d4f52e1f441ef2abdda3eb949cc0c4bJohn Spurlock        if (widgetView == null)
144dcc9681b0d4f52e1f441ef2abdda3eb949cc0c4bJohn Spurlock            return null;
145dcc9681b0d4f52e1f441ef2abdda3eb949cc0c4bJohn Spurlock
146dcc9681b0d4f52e1f441ef2abdda3eb949cc0c4bJohn Spurlock        ImageView preview = new ImageView(context);
14747cde77bc7ac5c3a1e486691596a7534ad855ff2John Spurlock        preview.setLayoutParams(new FrameLayout.LayoutParams(
14847cde77bc7ac5c3a1e486691596a7534ad855ff2John Spurlock                FrameLayout.LayoutParams.MATCH_PARENT,
14947cde77bc7ac5c3a1e486691596a7534ad855ff2John Spurlock                FrameLayout.LayoutParams.MATCH_PARENT));
150dcc9681b0d4f52e1f441ef2abdda3eb949cc0c4bJohn Spurlock        preview.setScaleType(ScaleType.FIT_CENTER);
151c4842c11932ea4f60fe7ae09b0a59660207e1587Svetoslav Ganov        preview.setContentDescription(preview.getContext().getString(
152c4842c11932ea4f60fe7ae09b0a59660207e1587Svetoslav Ganov                R.string.keyguard_accessibility_camera));
153dcc9681b0d4f52e1f441ef2abdda3eb949cc0c4bJohn Spurlock        CameraWidgetFrame cameraWidgetFrame = new CameraWidgetFrame(context, callbacks, launcher);
154dcc9681b0d4f52e1f441ef2abdda3eb949cc0c4bJohn Spurlock        cameraWidgetFrame.addView(preview);
155dcc9681b0d4f52e1f441ef2abdda3eb949cc0c4bJohn Spurlock        cameraWidgetFrame.mWidgetView = widgetView;
1564b976ea1af04f8c340ef7e0d79f73d7cdb5eb72eJohn Spurlock        preview.setOnClickListener(cameraWidgetFrame);
157dcc9681b0d4f52e1f441ef2abdda3eb949cc0c4bJohn Spurlock        return cameraWidgetFrame;
15886b6357e5eb91950eac7de7ffe29e5a4ad32903bJohn Spurlock    }
15986b6357e5eb91950eac7de7ffe29e5a4ad32903bJohn Spurlock
160dcc9681b0d4f52e1f441ef2abdda3eb949cc0c4bJohn Spurlock    private static View inflateWidgetView(Context context, CameraWidgetInfo widgetInfo) {
1614b976ea1af04f8c340ef7e0d79f73d7cdb5eb72eJohn Spurlock        if (DEBUG) Log.d(TAG, "inflateWidgetView: " + widgetInfo.contextPackage);
162dcc9681b0d4f52e1f441ef2abdda3eb949cc0c4bJohn Spurlock        View widgetView = null;
16386b6357e5eb91950eac7de7ffe29e5a4ad32903bJohn Spurlock        Exception exception = null;
16486b6357e5eb91950eac7de7ffe29e5a4ad32903bJohn Spurlock        try {
165dcc9681b0d4f52e1f441ef2abdda3eb949cc0c4bJohn Spurlock            Context cameraContext = context.createPackageContext(
166dcc9681b0d4f52e1f441ef2abdda3eb949cc0c4bJohn Spurlock                    widgetInfo.contextPackage, Context.CONTEXT_RESTRICTED);
16786b6357e5eb91950eac7de7ffe29e5a4ad32903bJohn Spurlock            LayoutInflater cameraInflater = (LayoutInflater)
16886b6357e5eb91950eac7de7ffe29e5a4ad32903bJohn Spurlock                    cameraContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
16986b6357e5eb91950eac7de7ffe29e5a4ad32903bJohn Spurlock            cameraInflater = cameraInflater.cloneInContext(cameraContext);
170dcc9681b0d4f52e1f441ef2abdda3eb949cc0c4bJohn Spurlock            widgetView = cameraInflater.inflate(widgetInfo.layoutId, null, false);
17186b6357e5eb91950eac7de7ffe29e5a4ad32903bJohn Spurlock        } catch (NameNotFoundException e) {
17286b6357e5eb91950eac7de7ffe29e5a4ad32903bJohn Spurlock            exception = e;
17386b6357e5eb91950eac7de7ffe29e5a4ad32903bJohn Spurlock        } catch (RuntimeException e) {
17486b6357e5eb91950eac7de7ffe29e5a4ad32903bJohn Spurlock            exception = e;
17586b6357e5eb91950eac7de7ffe29e5a4ad32903bJohn Spurlock        }
17686b6357e5eb91950eac7de7ffe29e5a4ad32903bJohn Spurlock        if (exception != null) {
17786b6357e5eb91950eac7de7ffe29e5a4ad32903bJohn Spurlock            Log.w(TAG, "Error creating camera widget view", exception);
17886b6357e5eb91950eac7de7ffe29e5a4ad32903bJohn Spurlock        }
179dcc9681b0d4f52e1f441ef2abdda3eb949cc0c4bJohn Spurlock        return widgetView;
180dcc9681b0d4f52e1f441ef2abdda3eb949cc0c4bJohn Spurlock    }
181dcc9681b0d4f52e1f441ef2abdda3eb949cc0c4bJohn Spurlock
182dcc9681b0d4f52e1f441ef2abdda3eb949cc0c4bJohn Spurlock    private static View inflateGenericWidgetView(Context context) {
1834b976ea1af04f8c340ef7e0d79f73d7cdb5eb72eJohn Spurlock        if (DEBUG) Log.d(TAG, "inflateGenericWidgetView");
184dcc9681b0d4f52e1f441ef2abdda3eb949cc0c4bJohn Spurlock        ImageView iv = new ImageView(context);
185dcc9681b0d4f52e1f441ef2abdda3eb949cc0c4bJohn Spurlock        iv.setImageResource(com.android.internal.R.drawable.ic_lockscreen_camera);
186dcc9681b0d4f52e1f441ef2abdda3eb949cc0c4bJohn Spurlock        iv.setScaleType(ScaleType.CENTER);
187dcc9681b0d4f52e1f441ef2abdda3eb949cc0c4bJohn Spurlock        iv.setBackgroundColor(Color.argb(127, 0, 0, 0));
188dcc9681b0d4f52e1f441ef2abdda3eb949cc0c4bJohn Spurlock        return iv;
18986b6357e5eb91950eac7de7ffe29e5a4ad32903bJohn Spurlock    }
19086b6357e5eb91950eac7de7ffe29e5a4ad32903bJohn Spurlock
191dcc9681b0d4f52e1f441ef2abdda3eb949cc0c4bJohn Spurlock    public void render() {
19237d84ae6051ab6d2add1e0ef51cf2aa2605c3225John Spurlock        final Throwable[] thrown = new Throwable[1];
19337d84ae6051ab6d2add1e0ef51cf2aa2605c3225John Spurlock        final Bitmap[] offscreen = new Bitmap[1];
19447cde77bc7ac5c3a1e486691596a7534ad855ff2John Spurlock        try {
19537d84ae6051ab6d2add1e0ef51cf2aa2605c3225John Spurlock            final int width = getRootView().getWidth();
19637d84ae6051ab6d2add1e0ef51cf2aa2605c3225John Spurlock            final int height = getRootView().getHeight();
197737798271e6e5b9466acef26ead061ecf6d0f292John Spurlock            if (mRenderedSize.x == width && mRenderedSize.y == height) {
19837d84ae6051ab6d2add1e0ef51cf2aa2605c3225John Spurlock                if (DEBUG) Log.d(TAG, String.format("Already rendered at size=%sx%s",
199737798271e6e5b9466acef26ead061ecf6d0f292John Spurlock                        width, height));
200737798271e6e5b9466acef26ead061ecf6d0f292John Spurlock                return;
201737798271e6e5b9466acef26ead061ecf6d0f292John Spurlock            }
20247cde77bc7ac5c3a1e486691596a7534ad855ff2John Spurlock            if (width == 0 || height == 0) {
20347cde77bc7ac5c3a1e486691596a7534ad855ff2John Spurlock                return;
20447cde77bc7ac5c3a1e486691596a7534ad855ff2John Spurlock            }
20537d84ae6051ab6d2add1e0ef51cf2aa2605c3225John Spurlock            final long start = SystemClock.uptimeMillis();
20637d84ae6051ab6d2add1e0ef51cf2aa2605c3225John Spurlock            offscreen[0] = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
20737d84ae6051ab6d2add1e0ef51cf2aa2605c3225John Spurlock            final Canvas c = new Canvas(offscreen[0]);
20847cde77bc7ac5c3a1e486691596a7534ad855ff2John Spurlock            mWidgetView.measure(
20947cde77bc7ac5c3a1e486691596a7534ad855ff2John Spurlock                    MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
21047cde77bc7ac5c3a1e486691596a7534ad855ff2John Spurlock                    MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
21147cde77bc7ac5c3a1e486691596a7534ad855ff2John Spurlock            mWidgetView.layout(0, 0, width, height);
21247cde77bc7ac5c3a1e486691596a7534ad855ff2John Spurlock            mWidgetView.draw(c);
21337d84ae6051ab6d2add1e0ef51cf2aa2605c3225John Spurlock
21437d84ae6051ab6d2add1e0ef51cf2aa2605c3225John Spurlock            final long end = SystemClock.uptimeMillis();
21537d84ae6051ab6d2add1e0ef51cf2aa2605c3225John Spurlock            if (DEBUG) Log.d(TAG, String.format(
21637d84ae6051ab6d2add1e0ef51cf2aa2605c3225John Spurlock                    "Rendered camera widget in %sms size=%sx%s instance=%s at %s",
21737d84ae6051ab6d2add1e0ef51cf2aa2605c3225John Spurlock                    end - start,
21837d84ae6051ab6d2add1e0ef51cf2aa2605c3225John Spurlock                    width, height,
2196275b3f1f3de7b0ca285e8f57a6d6014b0fa95b3John Spurlock                    instanceId(),
22037d84ae6051ab6d2add1e0ef51cf2aa2605c3225John Spurlock                    end));
221737798271e6e5b9466acef26ead061ecf6d0f292John Spurlock            mRenderedSize.set(width, height);
22247cde77bc7ac5c3a1e486691596a7534ad855ff2John Spurlock        } catch (Throwable t) {
22337d84ae6051ab6d2add1e0ef51cf2aa2605c3225John Spurlock            thrown[0] = t;
22447cde77bc7ac5c3a1e486691596a7534ad855ff2John Spurlock        }
22537d84ae6051ab6d2add1e0ef51cf2aa2605c3225John Spurlock
22637d84ae6051ab6d2add1e0ef51cf2aa2605c3225John Spurlock        mHandler.post(new Runnable() {
22737d84ae6051ab6d2add1e0ef51cf2aa2605c3225John Spurlock            @Override
22837d84ae6051ab6d2add1e0ef51cf2aa2605c3225John Spurlock            public void run() {
22937d84ae6051ab6d2add1e0ef51cf2aa2605c3225John Spurlock                if (thrown[0] == null) {
23037d84ae6051ab6d2add1e0ef51cf2aa2605c3225John Spurlock                    try {
23137d84ae6051ab6d2add1e0ef51cf2aa2605c3225John Spurlock                        ((ImageView) getChildAt(0)).setImageBitmap(offscreen[0]);
23237d84ae6051ab6d2add1e0ef51cf2aa2605c3225John Spurlock                    } catch (Throwable t) {
23337d84ae6051ab6d2add1e0ef51cf2aa2605c3225John Spurlock                        thrown[0] = t;
23437d84ae6051ab6d2add1e0ef51cf2aa2605c3225John Spurlock                    }
23537d84ae6051ab6d2add1e0ef51cf2aa2605c3225John Spurlock                }
23637d84ae6051ab6d2add1e0ef51cf2aa2605c3225John Spurlock                if (thrown[0] == null)
23737d84ae6051ab6d2add1e0ef51cf2aa2605c3225John Spurlock                    return;
23837d84ae6051ab6d2add1e0ef51cf2aa2605c3225John Spurlock
23937d84ae6051ab6d2add1e0ef51cf2aa2605c3225John Spurlock                Log.w(TAG, "Error rendering camera widget", thrown[0]);
24037d84ae6051ab6d2add1e0ef51cf2aa2605c3225John Spurlock                try {
24137d84ae6051ab6d2add1e0ef51cf2aa2605c3225John Spurlock                    removeAllViews();
24237d84ae6051ab6d2add1e0ef51cf2aa2605c3225John Spurlock                    final View genericView = inflateGenericWidgetView(mContext);
24337d84ae6051ab6d2add1e0ef51cf2aa2605c3225John Spurlock                    addView(genericView);
24437d84ae6051ab6d2add1e0ef51cf2aa2605c3225John Spurlock                } catch (Throwable t) {
24537d84ae6051ab6d2add1e0ef51cf2aa2605c3225John Spurlock                    Log.w(TAG, "Error inflating generic camera widget", t);
24637d84ae6051ab6d2add1e0ef51cf2aa2605c3225John Spurlock                }
24737d84ae6051ab6d2add1e0ef51cf2aa2605c3225John Spurlock            }});
24886b6357e5eb91950eac7de7ffe29e5a4ad32903bJohn Spurlock    }
24986b6357e5eb91950eac7de7ffe29e5a4ad32903bJohn Spurlock
25086b6357e5eb91950eac7de7ffe29e5a4ad32903bJohn Spurlock    private void transitionToCamera() {
251bb5c941149b66c0192736468bb60f47984dd5e1fJohn Spurlock        if (mTransitioning || mDown) return;
252cf69c56b8336e2bd5c8e20f948cc80ca53e0c25aJohn Spurlock
2534b976ea1af04f8c340ef7e0d79f73d7cdb5eb72eJohn Spurlock        mTransitioning = true;
254dcc9681b0d4f52e1f441ef2abdda3eb949cc0c4bJohn Spurlock
255cf69c56b8336e2bd5c8e20f948cc80ca53e0c25aJohn Spurlock        final View child = getChildAt(0);
256cf69c56b8336e2bd5c8e20f948cc80ca53e0c25aJohn Spurlock        final View root = getRootView();
257cf69c56b8336e2bd5c8e20f948cc80ca53e0c25aJohn Spurlock
258cf69c56b8336e2bd5c8e20f948cc80ca53e0c25aJohn Spurlock        final int startWidth = child.getWidth();
259cf69c56b8336e2bd5c8e20f948cc80ca53e0c25aJohn Spurlock        final int startHeight = child.getHeight();
260dcc9681b0d4f52e1f441ef2abdda3eb949cc0c4bJohn Spurlock
261cf69c56b8336e2bd5c8e20f948cc80ca53e0c25aJohn Spurlock        final int finishWidth = root.getWidth();
262cf69c56b8336e2bd5c8e20f948cc80ca53e0c25aJohn Spurlock        final int finishHeight = root.getHeight();
263dcc9681b0d4f52e1f441ef2abdda3eb949cc0c4bJohn Spurlock
264cf69c56b8336e2bd5c8e20f948cc80ca53e0c25aJohn Spurlock        final float scaleX = (float) finishWidth / startWidth;
265cf69c56b8336e2bd5c8e20f948cc80ca53e0c25aJohn Spurlock        final float scaleY = (float) finishHeight / startHeight;
266cf69c56b8336e2bd5c8e20f948cc80ca53e0c25aJohn Spurlock        final float scale = Math.round( Math.max(scaleX, scaleY) * 100) / 100f;
267cfc3086b18396df03f982fb98112649dc5b5a6f2Adam Powell
268cfc3086b18396df03f982fb98112649dc5b5a6f2Adam Powell        final int[] loc = new int[2];
269cf69c56b8336e2bd5c8e20f948cc80ca53e0c25aJohn Spurlock        root.getLocationInWindow(loc);
270cf69c56b8336e2bd5c8e20f948cc80ca53e0c25aJohn Spurlock        final int finishCenter = loc[1] + finishHeight / 2;
271cf69c56b8336e2bd5c8e20f948cc80ca53e0c25aJohn Spurlock
272cfc3086b18396df03f982fb98112649dc5b5a6f2Adam Powell        child.getLocationInWindow(loc);
273cf69c56b8336e2bd5c8e20f948cc80ca53e0c25aJohn Spurlock        final int startCenter = loc[1] + startHeight / 2;
274cf69c56b8336e2bd5c8e20f948cc80ca53e0c25aJohn Spurlock
275cf69c56b8336e2bd5c8e20f948cc80ca53e0c25aJohn Spurlock        if (DEBUG) Log.d(TAG, String.format("Transitioning to camera. " +
276cf69c56b8336e2bd5c8e20f948cc80ca53e0c25aJohn Spurlock                "(start=%sx%s, finish=%sx%s, scale=%s,%s, startCenter=%s, finishCenter=%s)",
277cf69c56b8336e2bd5c8e20f948cc80ca53e0c25aJohn Spurlock                startWidth, startHeight,
278cf69c56b8336e2bd5c8e20f948cc80ca53e0c25aJohn Spurlock                finishWidth, finishHeight,
279cf69c56b8336e2bd5c8e20f948cc80ca53e0c25aJohn Spurlock                scaleX, scaleY,
280cf69c56b8336e2bd5c8e20f948cc80ca53e0c25aJohn Spurlock                startCenter, finishCenter));
281cf69c56b8336e2bd5c8e20f948cc80ca53e0c25aJohn Spurlock
282e2ac5207f204ee26ba43c033d9ffb51f7daee2bdJohn Spurlock        enableWindowExitAnimation(false);
28386b6357e5eb91950eac7de7ffe29e5a4ad32903bJohn Spurlock        animate()
284dcc9681b0d4f52e1f441ef2abdda3eb949cc0c4bJohn Spurlock            .scaleX(scale)
285dcc9681b0d4f52e1f441ef2abdda3eb949cc0c4bJohn Spurlock            .scaleY(scale)
286cf69c56b8336e2bd5c8e20f948cc80ca53e0c25aJohn Spurlock            .translationY(finishCenter - startCenter)
287dcc9681b0d4f52e1f441ef2abdda3eb949cc0c4bJohn Spurlock            .setDuration(WIDGET_ANIMATION_DURATION)
28857f928fc4afc02d2fe45523efea687eee7f86c02John Spurlock            .withEndAction(mTransitionToCameraEndAction)
28986b6357e5eb91950eac7de7ffe29e5a4ad32903bJohn Spurlock            .start();
290cf69c56b8336e2bd5c8e20f948cc80ca53e0c25aJohn Spurlock
29186b6357e5eb91950eac7de7ffe29e5a4ad32903bJohn Spurlock        mCallbacks.onLaunchingCamera();
29286b6357e5eb91950eac7de7ffe29e5a4ad32903bJohn Spurlock    }
29386b6357e5eb91950eac7de7ffe29e5a4ad32903bJohn Spurlock
29457f928fc4afc02d2fe45523efea687eee7f86c02John Spurlock    private void recover() {
29557f928fc4afc02d2fe45523efea687eee7f86c02John Spurlock        if (DEBUG) Log.d(TAG, "recovering at " + SystemClock.uptimeMillis());
29657f928fc4afc02d2fe45523efea687eee7f86c02John Spurlock        mRecovering = true;
29757f928fc4afc02d2fe45523efea687eee7f86c02John Spurlock        animate()
29857f928fc4afc02d2fe45523efea687eee7f86c02John Spurlock            .scaleX(1)
29957f928fc4afc02d2fe45523efea687eee7f86c02John Spurlock            .scaleY(1)
30057f928fc4afc02d2fe45523efea687eee7f86c02John Spurlock            .translationY(0)
30157f928fc4afc02d2fe45523efea687eee7f86c02John Spurlock            .setDuration(WIDGET_ANIMATION_DURATION)
30257f928fc4afc02d2fe45523efea687eee7f86c02John Spurlock            .withEndAction(mRecoverEndAction)
30357f928fc4afc02d2fe45523efea687eee7f86c02John Spurlock            .start();
30457f928fc4afc02d2fe45523efea687eee7f86c02John Spurlock    }
30557f928fc4afc02d2fe45523efea687eee7f86c02John Spurlock
30686b6357e5eb91950eac7de7ffe29e5a4ad32903bJohn Spurlock    @Override
3074b976ea1af04f8c340ef7e0d79f73d7cdb5eb72eJohn Spurlock    public void onClick(View v) {
3084b976ea1af04f8c340ef7e0d79f73d7cdb5eb72eJohn Spurlock        if (DEBUG) Log.d(TAG, "clicked");
3094b976ea1af04f8c340ef7e0d79f73d7cdb5eb72eJohn Spurlock        if (mTransitioning) return;
310bb5c941149b66c0192736468bb60f47984dd5e1fJohn Spurlock        if (mActive) {
3114b976ea1af04f8c340ef7e0d79f73d7cdb5eb72eJohn Spurlock            cancelTransitionToCamera();
3124b976ea1af04f8c340ef7e0d79f73d7cdb5eb72eJohn Spurlock            transitionToCamera();
3134b976ea1af04f8c340ef7e0d79f73d7cdb5eb72eJohn Spurlock        }
3144b976ea1af04f8c340ef7e0d79f73d7cdb5eb72eJohn Spurlock    }
3154b976ea1af04f8c340ef7e0d79f73d7cdb5eb72eJohn Spurlock
3164b976ea1af04f8c340ef7e0d79f73d7cdb5eb72eJohn Spurlock    @Override
3176275b3f1f3de7b0ca285e8f57a6d6014b0fa95b3John Spurlock    protected void onDetachedFromWindow() {
3186275b3f1f3de7b0ca285e8f57a6d6014b0fa95b3John Spurlock        if (DEBUG) Log.d(TAG, "onDetachedFromWindow: instance " + instanceId()
3196275b3f1f3de7b0ca285e8f57a6d6014b0fa95b3John Spurlock                + " at " + SystemClock.uptimeMillis());
3206275b3f1f3de7b0ca285e8f57a6d6014b0fa95b3John Spurlock        super.onDetachedFromWindow();
3216275b3f1f3de7b0ca285e8f57a6d6014b0fa95b3John Spurlock        KeyguardUpdateMonitor.getInstance(mContext).removeCallback(mCallback);
32257f928fc4afc02d2fe45523efea687eee7f86c02John Spurlock        cancelTransitionToCamera();
32357f928fc4afc02d2fe45523efea687eee7f86c02John Spurlock        mHandler.removeCallbacks(mRecoverRunnable);
32486b6357e5eb91950eac7de7ffe29e5a4ad32903bJohn Spurlock    }
32586b6357e5eb91950eac7de7ffe29e5a4ad32903bJohn Spurlock
32686b6357e5eb91950eac7de7ffe29e5a4ad32903bJohn Spurlock    @Override
32786b6357e5eb91950eac7de7ffe29e5a4ad32903bJohn Spurlock    public void onActive(boolean isActive) {
3284b976ea1af04f8c340ef7e0d79f73d7cdb5eb72eJohn Spurlock        mActive = isActive;
3294b976ea1af04f8c340ef7e0d79f73d7cdb5eb72eJohn Spurlock        if (mActive) {
3304b976ea1af04f8c340ef7e0d79f73d7cdb5eb72eJohn Spurlock            rescheduleTransitionToCamera();
33186b6357e5eb91950eac7de7ffe29e5a4ad32903bJohn Spurlock        } else {
33286b6357e5eb91950eac7de7ffe29e5a4ad32903bJohn Spurlock            reset();
33386b6357e5eb91950eac7de7ffe29e5a4ad32903bJohn Spurlock        }
33486b6357e5eb91950eac7de7ffe29e5a4ad32903bJohn Spurlock    }
33586b6357e5eb91950eac7de7ffe29e5a4ad32903bJohn Spurlock
3364b976ea1af04f8c340ef7e0d79f73d7cdb5eb72eJohn Spurlock    @Override
337bb5c941149b66c0192736468bb60f47984dd5e1fJohn Spurlock    public boolean onUserInteraction(MotionEvent event) {
338bb5c941149b66c0192736468bb60f47984dd5e1fJohn Spurlock        if (mTransitioning) {
339bb5c941149b66c0192736468bb60f47984dd5e1fJohn Spurlock            if (DEBUG) Log.d(TAG, "onUserInteraction eaten: mTransitioning");
340bb5c941149b66c0192736468bb60f47984dd5e1fJohn Spurlock            return true;
341bb5c941149b66c0192736468bb60f47984dd5e1fJohn Spurlock        }
342bb5c941149b66c0192736468bb60f47984dd5e1fJohn Spurlock
343bb5c941149b66c0192736468bb60f47984dd5e1fJohn Spurlock        getLocationOnScreen(mScreenLocation);
344bb5c941149b66c0192736468bb60f47984dd5e1fJohn Spurlock        int rawBottom = mScreenLocation[1] + getHeight();
345bb5c941149b66c0192736468bb60f47984dd5e1fJohn Spurlock        if (event.getRawY() > rawBottom) {
346bb5c941149b66c0192736468bb60f47984dd5e1fJohn Spurlock            if (DEBUG) Log.d(TAG, "onUserInteraction eaten: below widget");
347bb5c941149b66c0192736468bb60f47984dd5e1fJohn Spurlock            return true;
348bb5c941149b66c0192736468bb60f47984dd5e1fJohn Spurlock        }
349bb5c941149b66c0192736468bb60f47984dd5e1fJohn Spurlock
350bb5c941149b66c0192736468bb60f47984dd5e1fJohn Spurlock        int action = event.getAction();
3514b976ea1af04f8c340ef7e0d79f73d7cdb5eb72eJohn Spurlock        mDown = action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_MOVE;
352bb5c941149b66c0192736468bb60f47984dd5e1fJohn Spurlock        if (mActive) {
3534b976ea1af04f8c340ef7e0d79f73d7cdb5eb72eJohn Spurlock            rescheduleTransitionToCamera();
3544b976ea1af04f8c340ef7e0d79f73d7cdb5eb72eJohn Spurlock        }
355bb5c941149b66c0192736468bb60f47984dd5e1fJohn Spurlock        if (DEBUG) Log.d(TAG, "onUserInteraction observed, not eaten");
3564b976ea1af04f8c340ef7e0d79f73d7cdb5eb72eJohn Spurlock        return false;
3574b976ea1af04f8c340ef7e0d79f73d7cdb5eb72eJohn Spurlock    }
3584b976ea1af04f8c340ef7e0d79f73d7cdb5eb72eJohn Spurlock
3594b976ea1af04f8c340ef7e0d79f73d7cdb5eb72eJohn Spurlock    @Override
3604b976ea1af04f8c340ef7e0d79f73d7cdb5eb72eJohn Spurlock    protected void onFocusLost() {
36157f928fc4afc02d2fe45523efea687eee7f86c02John Spurlock        if (DEBUG) Log.d(TAG, "onFocusLost at " + SystemClock.uptimeMillis());
3624b976ea1af04f8c340ef7e0d79f73d7cdb5eb72eJohn Spurlock        cancelTransitionToCamera();
3634b976ea1af04f8c340ef7e0d79f73d7cdb5eb72eJohn Spurlock        super.onFocusLost();
3644b976ea1af04f8c340ef7e0d79f73d7cdb5eb72eJohn Spurlock    }
3654b976ea1af04f8c340ef7e0d79f73d7cdb5eb72eJohn Spurlock
366dbe24b7def8df3a539790827d3f395f4d933802bJohn Spurlock    public void onScreenTurnedOff() {
367dbe24b7def8df3a539790827d3f395f4d933802bJohn Spurlock        if (DEBUG) Log.d(TAG, "onScreenTurnedOff");
368dbe24b7def8df3a539790827d3f395f4d933802bJohn Spurlock        reset();
369dbe24b7def8df3a539790827d3f395f4d933802bJohn Spurlock    }
370dbe24b7def8df3a539790827d3f395f4d933802bJohn Spurlock
3714b976ea1af04f8c340ef7e0d79f73d7cdb5eb72eJohn Spurlock    private void rescheduleTransitionToCamera() {
3724b976ea1af04f8c340ef7e0d79f73d7cdb5eb72eJohn Spurlock        if (DEBUG) Log.d(TAG, "rescheduleTransitionToCamera at " + SystemClock.uptimeMillis());
3734b976ea1af04f8c340ef7e0d79f73d7cdb5eb72eJohn Spurlock        mHandler.removeCallbacks(mTransitionToCameraRunnable);
3744b976ea1af04f8c340ef7e0d79f73d7cdb5eb72eJohn Spurlock        mHandler.postDelayed(mTransitionToCameraRunnable, WIDGET_WAIT_DURATION);
3754b976ea1af04f8c340ef7e0d79f73d7cdb5eb72eJohn Spurlock    }
3764b976ea1af04f8c340ef7e0d79f73d7cdb5eb72eJohn Spurlock
3774b976ea1af04f8c340ef7e0d79f73d7cdb5eb72eJohn Spurlock    private void cancelTransitionToCamera() {
3784b976ea1af04f8c340ef7e0d79f73d7cdb5eb72eJohn Spurlock        if (DEBUG) Log.d(TAG, "cancelTransitionToCamera at " + SystemClock.uptimeMillis());
3794b976ea1af04f8c340ef7e0d79f73d7cdb5eb72eJohn Spurlock        mHandler.removeCallbacks(mTransitionToCameraRunnable);
3804b976ea1af04f8c340ef7e0d79f73d7cdb5eb72eJohn Spurlock    }
3814b976ea1af04f8c340ef7e0d79f73d7cdb5eb72eJohn Spurlock
38286b6357e5eb91950eac7de7ffe29e5a4ad32903bJohn Spurlock    private void onCameraLaunched() {
38357f928fc4afc02d2fe45523efea687eee7f86c02John Spurlock        mCallbacks.onCameraLaunchedSuccessfully();
3844b976ea1af04f8c340ef7e0d79f73d7cdb5eb72eJohn Spurlock        reset();
38586b6357e5eb91950eac7de7ffe29e5a4ad32903bJohn Spurlock    }
38686b6357e5eb91950eac7de7ffe29e5a4ad32903bJohn Spurlock
38786b6357e5eb91950eac7de7ffe29e5a4ad32903bJohn Spurlock    private void reset() {
38857f928fc4afc02d2fe45523efea687eee7f86c02John Spurlock        if (DEBUG) Log.d(TAG, "reset at " + SystemClock.uptimeMillis());
3894b976ea1af04f8c340ef7e0d79f73d7cdb5eb72eJohn Spurlock        mLaunchCameraStart = 0;
3904b976ea1af04f8c340ef7e0d79f73d7cdb5eb72eJohn Spurlock        mTransitioning = false;
39157f928fc4afc02d2fe45523efea687eee7f86c02John Spurlock        mRecovering = false;
3924b976ea1af04f8c340ef7e0d79f73d7cdb5eb72eJohn Spurlock        mDown = false;
3934b976ea1af04f8c340ef7e0d79f73d7cdb5eb72eJohn Spurlock        cancelTransitionToCamera();
39457f928fc4afc02d2fe45523efea687eee7f86c02John Spurlock        mHandler.removeCallbacks(mRecoverRunnable);
39586b6357e5eb91950eac7de7ffe29e5a4ad32903bJohn Spurlock        animate().cancel();
39686b6357e5eb91950eac7de7ffe29e5a4ad32903bJohn Spurlock        setScaleX(1);
39786b6357e5eb91950eac7de7ffe29e5a4ad32903bJohn Spurlock        setScaleY(1);
398cfc3086b18396df03f982fb98112649dc5b5a6f2Adam Powell        setTranslationY(0);
399e2ac5207f204ee26ba43c033d9ffb51f7daee2bdJohn Spurlock        enableWindowExitAnimation(true);
40086b6357e5eb91950eac7de7ffe29e5a4ad32903bJohn Spurlock    }
40186b6357e5eb91950eac7de7ffe29e5a4ad32903bJohn Spurlock
402dcc9681b0d4f52e1f441ef2abdda3eb949cc0c4bJohn Spurlock    @Override
403737798271e6e5b9466acef26ead061ecf6d0f292John Spurlock    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
404737798271e6e5b9466acef26ead061ecf6d0f292John Spurlock        if (DEBUG) Log.d(TAG, String.format("onSizeChanged new=%sx%s old=%sx%s at %s",
405737798271e6e5b9466acef26ead061ecf6d0f292John Spurlock                w, h, oldw, oldh, SystemClock.uptimeMillis()));
40637d84ae6051ab6d2add1e0ef51cf2aa2605c3225John Spurlock        final Handler worker =  getWorkerHandler();
40737d84ae6051ab6d2add1e0ef51cf2aa2605c3225John Spurlock        (worker != null ? worker : mHandler).post(mRenderRunnable);
408737798271e6e5b9466acef26ead061ecf6d0f292John Spurlock        super.onSizeChanged(w, h, oldw, oldh);
40986b6357e5eb91950eac7de7ffe29e5a4ad32903bJohn Spurlock    }
410e2ac5207f204ee26ba43c033d9ffb51f7daee2bdJohn Spurlock
411e2ac5207f204ee26ba43c033d9ffb51f7daee2bdJohn Spurlock    private void enableWindowExitAnimation(boolean isEnabled) {
412e2ac5207f204ee26ba43c033d9ffb51f7daee2bdJohn Spurlock        View root = getRootView();
413737798271e6e5b9466acef26ead061ecf6d0f292John Spurlock        ViewGroup.LayoutParams lp = root.getLayoutParams();
414737798271e6e5b9466acef26ead061ecf6d0f292John Spurlock        if (!(lp instanceof WindowManager.LayoutParams))
415737798271e6e5b9466acef26ead061ecf6d0f292John Spurlock            return;
416737798271e6e5b9466acef26ead061ecf6d0f292John Spurlock        WindowManager.LayoutParams wlp = (WindowManager.LayoutParams) lp;
417e2ac5207f204ee26ba43c033d9ffb51f7daee2bdJohn Spurlock        int newWindowAnimations = isEnabled ? com.android.internal.R.style.Animation_LockScreen : 0;
418737798271e6e5b9466acef26ead061ecf6d0f292John Spurlock        if (newWindowAnimations != wlp.windowAnimations) {
41957f928fc4afc02d2fe45523efea687eee7f86c02John Spurlock            if (DEBUG) Log.d(TAG, "setting windowAnimations to: " + newWindowAnimations
42057f928fc4afc02d2fe45523efea687eee7f86c02John Spurlock                    + " at " + SystemClock.uptimeMillis());
421737798271e6e5b9466acef26ead061ecf6d0f292John Spurlock            wlp.windowAnimations = newWindowAnimations;
422737798271e6e5b9466acef26ead061ecf6d0f292John Spurlock            mWindowManager.updateViewLayout(root, wlp);
423e2ac5207f204ee26ba43c033d9ffb51f7daee2bdJohn Spurlock        }
424e2ac5207f204ee26ba43c033d9ffb51f7daee2bdJohn Spurlock    }
4256275b3f1f3de7b0ca285e8f57a6d6014b0fa95b3John Spurlock
4266275b3f1f3de7b0ca285e8f57a6d6014b0fa95b3John Spurlock    private void onKeyguardVisibilityChanged(boolean showing) {
4276275b3f1f3de7b0ca285e8f57a6d6014b0fa95b3John Spurlock        if (DEBUG) Log.d(TAG, "onKeyguardVisibilityChanged " + showing
4286275b3f1f3de7b0ca285e8f57a6d6014b0fa95b3John Spurlock                + " at " + SystemClock.uptimeMillis());
4296275b3f1f3de7b0ca285e8f57a6d6014b0fa95b3John Spurlock        if (mTransitioning && !showing) {
4306275b3f1f3de7b0ca285e8f57a6d6014b0fa95b3John Spurlock          mTransitioning = false;
43157f928fc4afc02d2fe45523efea687eee7f86c02John Spurlock          mRecovering = false;
43257f928fc4afc02d2fe45523efea687eee7f86c02John Spurlock          mHandler.removeCallbacks(mRecoverRunnable);
4336275b3f1f3de7b0ca285e8f57a6d6014b0fa95b3John Spurlock          if (mLaunchCameraStart > 0) {
4346275b3f1f3de7b0ca285e8f57a6d6014b0fa95b3John Spurlock              long launchTime = SystemClock.uptimeMillis() - mLaunchCameraStart;
4356275b3f1f3de7b0ca285e8f57a6d6014b0fa95b3John Spurlock              if (DEBUG) Log.d(TAG, String.format("Camera took %sms to launch", launchTime));
4366275b3f1f3de7b0ca285e8f57a6d6014b0fa95b3John Spurlock              mLaunchCameraStart = 0;
4376275b3f1f3de7b0ca285e8f57a6d6014b0fa95b3John Spurlock              onCameraLaunched();
4386275b3f1f3de7b0ca285e8f57a6d6014b0fa95b3John Spurlock          }
4396275b3f1f3de7b0ca285e8f57a6d6014b0fa95b3John Spurlock        }
4406275b3f1f3de7b0ca285e8f57a6d6014b0fa95b3John Spurlock    }
4416275b3f1f3de7b0ca285e8f57a6d6014b0fa95b3John Spurlock
44257f928fc4afc02d2fe45523efea687eee7f86c02John Spurlock    private void onSecureCameraActivityStarted() {
44357f928fc4afc02d2fe45523efea687eee7f86c02John Spurlock        if (DEBUG) Log.d(TAG, "onSecureCameraActivityStarted at " + SystemClock.uptimeMillis());
44457f928fc4afc02d2fe45523efea687eee7f86c02John Spurlock        mHandler.postDelayed(mRecoverRunnable, RECOVERY_DELAY);
44557f928fc4afc02d2fe45523efea687eee7f86c02John Spurlock    }
44657f928fc4afc02d2fe45523efea687eee7f86c02John Spurlock
4476275b3f1f3de7b0ca285e8f57a6d6014b0fa95b3John Spurlock    private String instanceId() {
4486275b3f1f3de7b0ca285e8f57a6d6014b0fa95b3John Spurlock        return Integer.toHexString(hashCode());
4496275b3f1f3de7b0ca285e8f57a6d6014b0fa95b3John Spurlock    }
45086b6357e5eb91950eac7de7ffe29e5a4ad32903bJohn Spurlock}
451