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