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