CameraWidgetFrame.java revision 47cde77bc7ac5c3a1e486691596a7534ad855ff2
1/*
2 * Copyright (C) 2012 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
17package com.android.internal.policy.impl.keyguard;
18
19import android.content.Context;
20import android.content.pm.PackageManager.NameNotFoundException;
21import android.graphics.Bitmap;
22import android.graphics.Canvas;
23import android.graphics.Color;
24import android.os.Handler;
25import android.os.SystemClock;
26import android.util.Log;
27import android.view.LayoutInflater;
28import android.view.View;
29import android.widget.FrameLayout;
30import android.widget.ImageView;
31import android.widget.ImageView.ScaleType;
32
33import com.android.internal.policy.impl.keyguard.KeyguardActivityLauncher.CameraWidgetInfo;
34
35public class CameraWidgetFrame extends KeyguardWidgetFrame {
36    private static final String TAG = CameraWidgetFrame.class.getSimpleName();
37    private static final boolean DEBUG = KeyguardHostView.DEBUG;
38    private static final int WIDGET_ANIMATION_DURATION = 250;
39
40    interface Callbacks {
41        void onLaunchingCamera();
42        void onCameraLaunched();
43    }
44
45    private final Handler mHandler = new Handler();
46    private final KeyguardActivityLauncher mActivityLauncher;
47    private final Callbacks mCallbacks;
48
49    private View mWidgetView;
50    private long mLaunchCameraStart;
51    private boolean mRendered;
52
53    private final Runnable mLaunchCameraRunnable = new Runnable() {
54        @Override
55        public void run() {
56            mLaunchCameraStart = SystemClock.uptimeMillis();
57            mActivityLauncher.launchCamera();
58        }};
59
60    private final Runnable mRenderRunnable = new Runnable() {
61        @Override
62        public void run() {
63            render();
64        }};
65
66    private CameraWidgetFrame(Context context, Callbacks callbacks,
67            KeyguardActivityLauncher activityLauncher) {
68        super(context);
69
70        mCallbacks = callbacks;
71        mActivityLauncher = activityLauncher;
72    }
73
74    public static CameraWidgetFrame create(Context context, Callbacks callbacks,
75            KeyguardActivityLauncher launcher) {
76        if (context == null || callbacks == null || launcher == null)
77            return null;
78
79        CameraWidgetInfo widgetInfo = launcher.getCameraWidgetInfo();
80        if (widgetInfo == null)
81            return null;
82        View widgetView = widgetInfo.layoutId > 0 ?
83                inflateWidgetView(context, widgetInfo) :
84                inflateGenericWidgetView(context);
85        if (widgetView == null)
86            return null;
87
88        ImageView preview = new ImageView(context);
89        preview.setLayoutParams(new FrameLayout.LayoutParams(
90                FrameLayout.LayoutParams.MATCH_PARENT,
91                FrameLayout.LayoutParams.MATCH_PARENT));
92        preview.setScaleType(ScaleType.FIT_CENTER);
93        CameraWidgetFrame cameraWidgetFrame = new CameraWidgetFrame(context, callbacks, launcher);
94        cameraWidgetFrame.addView(preview);
95        cameraWidgetFrame.mWidgetView = widgetView;
96        return cameraWidgetFrame;
97    }
98
99    private static View inflateWidgetView(Context context, CameraWidgetInfo widgetInfo) {
100        View widgetView = null;
101        Exception exception = null;
102        try {
103            Context cameraContext = context.createPackageContext(
104                    widgetInfo.contextPackage, Context.CONTEXT_RESTRICTED);
105            LayoutInflater cameraInflater = (LayoutInflater)
106                    cameraContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
107            cameraInflater = cameraInflater.cloneInContext(cameraContext);
108            widgetView = cameraInflater.inflate(widgetInfo.layoutId, null, false);
109        } catch (NameNotFoundException e) {
110            exception = e;
111        } catch (RuntimeException e) {
112            exception = e;
113        }
114        if (exception != null) {
115            Log.w(TAG, "Error creating camera widget view", exception);
116        }
117        return widgetView;
118    }
119
120    private static View inflateGenericWidgetView(Context context) {
121        ImageView iv = new ImageView(context);
122        iv.setImageResource(com.android.internal.R.drawable.ic_lockscreen_camera);
123        iv.setScaleType(ScaleType.CENTER);
124        iv.setBackgroundColor(Color.argb(127, 0, 0, 0));
125        return iv;
126    }
127
128    public void render() {
129        if (mRendered) return;
130
131        try {
132            int width = getRootView().getWidth();
133            int height = getRootView().getHeight();
134            if (DEBUG) Log.d(TAG, String.format("render [%sx%s] %s",
135                    width, height, Integer.toHexString(hashCode())));
136            if (width == 0 || height == 0) {
137                return;
138            }
139            Bitmap offscreen = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
140            Canvas c = new Canvas(offscreen);
141            mWidgetView.measure(
142                    MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
143                    MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
144            mWidgetView.layout(0, 0, width, height);
145            mWidgetView.draw(c);
146            ((ImageView)getChildAt(0)).setImageBitmap(offscreen);
147            mRendered = true;
148        } catch (Throwable t) {
149            Log.w(TAG, "Error rendering camera widget", t);
150            removeAllViews();
151            View genericView = inflateGenericWidgetView(mContext);
152            addView(genericView);
153        }
154    }
155
156    private void transitionToCamera() {
157        int startWidth = getChildAt(0).getWidth();
158        int startHeight = getChildAt(0).getHeight();
159
160        int finishWidth = getRootView().getWidth();
161        int finishHeight = getRootView().getHeight();
162
163        float scaleX = (float) finishWidth / startWidth;
164        float scaleY = (float) finishHeight / startHeight;
165
166        float scale = Math.max(scaleX, scaleY);
167        animate()
168            .scaleX(scale)
169            .scaleY(scale)
170            .setDuration(WIDGET_ANIMATION_DURATION)
171            .withEndAction(mLaunchCameraRunnable)
172            .start();
173        mCallbacks.onLaunchingCamera();
174    }
175
176    @Override
177    public void onWindowFocusChanged(boolean hasWindowFocus) {
178        super.onWindowFocusChanged(hasWindowFocus);
179
180        if (!hasWindowFocus) {
181            if (mLaunchCameraStart > 0) {
182                long launchTime = SystemClock.uptimeMillis() - mLaunchCameraStart;
183                if (DEBUG) Log.d(TAG, String.format("Camera took %sms to launch", launchTime));
184                mLaunchCameraStart = 0;
185                onCameraLaunched();
186            }
187        }
188    }
189
190    @Override
191    public void onActive(boolean isActive) {
192        if (isActive) {
193            mHandler.post(new Runnable(){
194                @Override
195                public void run() {
196                    transitionToCamera();
197                }});
198        } else {
199            reset();
200        }
201    }
202
203    private void onCameraLaunched() {
204        reset();
205        mCallbacks.onCameraLaunched();
206    }
207
208    private void reset() {
209        animate().cancel();
210        setScaleX(1);
211        setScaleY(1);
212    }
213
214    @Override
215    protected void onAttachedToWindow() {
216        super.onAttachedToWindow();
217        mHandler.post(mRenderRunnable);
218    }
219}
220