ActivityBase.java revision 296d27772b9543d55820e1d24d900fea959f1b7a
1/*
2 * Copyright (C) 2009 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.camera;
18
19import android.app.Activity;
20import android.app.KeyguardManager;
21import android.content.ContentResolver;
22import android.content.Context;
23import android.content.Intent;
24import android.content.pm.ActivityInfo;
25import android.hardware.Camera.Parameters;
26import android.os.AsyncTask;
27import android.os.Bundle;
28import android.util.Log;
29import android.view.KeyEvent;
30import android.view.View;
31import android.view.WindowManager;
32
33import com.android.camera.ui.PopupManager;
34import com.android.camera.ui.RotateImageView;
35
36import java.io.File;
37
38/**
39 * Superclass of Camera and VideoCamera activities.
40 */
41abstract public class ActivityBase extends Activity {
42    private static final String TAG = "ActivityBase";
43    private static boolean LOGV = false;
44    private int mResultCodeForTesting;
45    private boolean mOnResumePending;
46    private Intent mResultDataForTesting;
47    private OnScreenHint mStorageHint;
48    // The bitmap of the last captured picture thumbnail and the URI of the
49    // original picture.
50    protected Thumbnail mThumbnail;
51    // An imageview showing showing the last captured picture thumbnail.
52    protected RotateImageView mThumbnailView;
53    protected int mThumbnailViewWidth; // layout width of the thumbnail
54    protected AsyncTask<Void, Void, Thumbnail> mLoadThumbnailTask;
55    protected boolean mOpenCameraFail;
56    protected boolean mCameraDisabled;
57    protected CameraManager.CameraProxy mCameraDevice;
58    protected Parameters mParameters;
59
60    // multiple cameras support
61    protected int mNumberOfCameras;
62    protected int mCameraId;
63
64    protected class CameraOpenThread extends Thread {
65        @Override
66        public void run() {
67            try {
68                mCameraDevice = Util.openCamera(ActivityBase.this, mCameraId);
69                mParameters = mCameraDevice.getParameters();
70            } catch (CameraHardwareException e) {
71                mOpenCameraFail = true;
72            } catch (CameraDisabledException e) {
73                mCameraDisabled = true;
74            }
75        }
76    }
77
78    @Override
79    public void onCreate(Bundle icicle) {
80        if (Util.isTabletUI()) {
81            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
82        } else {
83            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
84        }
85        getWindow().addFlags(WindowManager.LayoutParams.FLAG_SECURE);
86        super.onCreate(icicle);
87    }
88
89    @Override
90    public void onWindowFocusChanged(boolean hasFocus) {
91        if (LOGV) Log.v(TAG, "onWindowFocusChanged.hasFocus=" + hasFocus
92                + ".mOnResumePending=" + mOnResumePending);
93        if (hasFocus && mOnResumePending) {
94            doOnResume();
95            mOnResumePending = false;
96        }
97    }
98
99    @Override
100    protected void onResume() {
101        super.onResume();
102        // Don't grab the camera if in use by lockscreen. For example, face
103        // unlock may be using the camera. Camera may be already opened in
104        // onCreate. doOnResume should continue if mCameraDevice != null.
105        // Suppose camera app is in the foreground. If users turn off and turn
106        // on the screen very fast, camera app can still have the focus when the
107        // lock screen shows up. The keyguard takes input focus, so the camera
108        // app will lose focus when it is displayed.
109        if (LOGV) Log.v(TAG, "onResume. hasWindowFocus()=" + hasWindowFocus());
110        if (mCameraDevice == null && isKeyguardLocked()) {
111            if (LOGV) Log.v(TAG, "onResume. mOnResumePending=true");
112            mOnResumePending = true;
113        } else {
114            if (LOGV) Log.v(TAG, "onResume. mOnResumePending=false");
115            doOnResume();
116            mOnResumePending = false;
117        }
118    }
119
120    @Override
121    protected void onPause() {
122        if (LOGV) Log.v(TAG, "onPause");
123        saveThumbnailToFile();
124        super.onPause();
125
126        if (mLoadThumbnailTask != null) {
127            mLoadThumbnailTask.cancel(true);
128            mLoadThumbnailTask = null;
129        }
130
131        if (mStorageHint != null) {
132            mStorageHint.cancel();
133            mStorageHint = null;
134        }
135
136        mOnResumePending = false;
137    }
138
139    // Put the code of onResume in this method.
140    abstract protected void doOnResume();
141
142    @Override
143    public boolean onSearchRequested() {
144        return false;
145    }
146
147    @Override
148    public boolean onKeyDown(int keyCode, KeyEvent event) {
149        // Prevent software keyboard or voice search from showing up.
150        if (keyCode == KeyEvent.KEYCODE_SEARCH
151                || keyCode == KeyEvent.KEYCODE_MENU) {
152            if (event.isLongPress()) return true;
153        }
154
155        return super.onKeyDown(keyCode, event);
156    }
157
158    protected void setResultEx(int resultCode) {
159        mResultCodeForTesting = resultCode;
160        setResult(resultCode);
161    }
162
163    protected void setResultEx(int resultCode, Intent data) {
164        mResultCodeForTesting = resultCode;
165        mResultDataForTesting = data;
166        setResult(resultCode, data);
167    }
168
169    public int getResultCode() {
170        return mResultCodeForTesting;
171    }
172
173    public Intent getResultData() {
174        return mResultDataForTesting;
175    }
176
177    @Override
178    protected void onDestroy() {
179        PopupManager.removeInstance(this);
180        super.onDestroy();
181    }
182
183    private boolean isKeyguardLocked() {
184        KeyguardManager kgm = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);
185        if (LOGV) {
186            if (kgm != null) {
187                Log.v(TAG, "kgm.isKeyguardLocked()="+kgm.isKeyguardLocked()
188                        + ". kgm.isKeyguardSecure()="+kgm.isKeyguardSecure());
189            }
190        }
191        // isKeyguardSecure excludes the slide lock case.
192        return (kgm != null) && kgm.isKeyguardLocked() && kgm.isKeyguardSecure();
193    }
194
195    protected void updateStorageHint(long storageSpace) {
196        String message = null;
197        if (storageSpace == Storage.UNAVAILABLE) {
198            message = getString(R.string.no_storage);
199        } else if (storageSpace == Storage.PREPARING) {
200            message = getString(R.string.preparing_sd);
201        } else if (storageSpace == Storage.UNKNOWN_SIZE) {
202            message = getString(R.string.access_sd_fail);
203        } else if (storageSpace < Storage.LOW_STORAGE_THRESHOLD) {
204            message = getString(R.string.spaceIsLow_content);
205        }
206
207        if (message != null) {
208            if (mStorageHint == null) {
209                mStorageHint = OnScreenHint.makeText(this, message);
210            } else {
211                mStorageHint.setText(message);
212            }
213            mStorageHint.show();
214        } else if (mStorageHint != null) {
215            mStorageHint.cancel();
216            mStorageHint = null;
217        }
218    }
219
220    private void updateThumbnailView() {
221        if (mThumbnail != null) {
222            mThumbnailView.setBitmap(mThumbnail.getBitmap());
223            mThumbnailView.setVisibility(View.VISIBLE);
224        } else {
225            mThumbnailView.setBitmap(null);
226            mThumbnailView.setVisibility(View.GONE);
227        }
228    }
229
230    protected void getLastThumbnail() {
231        mThumbnail = ThumbnailHolder.getLastThumbnail(getContentResolver());
232        // Suppose users tap the thumbnail view, go to the gallery, delete the
233        // image, and coming back to the camera. Thumbnail file will be invalid.
234        // Since the new thumbnail will be loaded in another thread later, the
235        // view should be set to gone to prevent from opening the invalid image.
236        updateThumbnailView();
237        if (mThumbnail == null) {
238            mLoadThumbnailTask = new LoadThumbnailTask().execute();
239        }
240    }
241
242    private class LoadThumbnailTask extends AsyncTask<Void, Void, Thumbnail> {
243        @Override
244        protected Thumbnail doInBackground(Void... params) {
245            // Load the thumbnail from the file.
246            ContentResolver resolver = getContentResolver();
247            Thumbnail t = Thumbnail.getLastThumbnailFromFile(getFilesDir(), resolver);
248
249            if (isCancelled()) return null;
250
251            if (t == null) {
252                // Load the thumbnail from the media provider.
253                t = Thumbnail.getLastThumbnailFromContentResolver(resolver);
254            }
255            return t;
256        }
257
258        @Override
259        protected void onPostExecute(Thumbnail thumbnail) {
260            mThumbnail = thumbnail;
261            updateThumbnailView();
262        }
263    }
264
265    protected void gotoGallery() {
266        Util.viewUri(mThumbnail.getUri(), this);
267    }
268
269    protected void saveThumbnailToFile() {
270        if (mThumbnail != null && !mThumbnail.fromFile()) {
271            new SaveThumbnailTask().execute(mThumbnail);
272        }
273    }
274
275    private class SaveThumbnailTask extends AsyncTask<Thumbnail, Void, Void> {
276        @Override
277        protected Void doInBackground(Thumbnail... params) {
278            final int n = params.length;
279            final File filesDir = getFilesDir();
280            for (int i = 0; i < n; i++) {
281                params[i].saveLastThumbnailToFile(filesDir);
282            }
283            return null;
284        }
285    }
286}
287