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