blob: 029b8a34882608bf40800bd095591c365a06c067 [file] [log] [blame]
Michael Kolb8872c232013-01-29 10:33:22 -08001/*
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.camera;
18
Doris Liu742cd5b2013-09-12 16:17:43 -070019import android.animation.Animator;
Mangesh Ghiwarea5682ab2013-09-19 09:24:23 -070020import android.annotation.TargetApi;
ztenghuifa9e2cc2013-08-09 17:37:15 -070021import android.app.ActionBar;
Doris Liu6432cd62013-06-13 17:20:31 -070022import android.app.Activity;
Angus Kong01054e92013-12-10 11:06:18 -080023import android.app.AlertDialog;
Mangesh Ghiware30968d02013-10-02 14:38:12 -070024import android.content.ActivityNotFoundException;
Doris Liub84b9732013-06-18 17:14:26 -070025import android.content.BroadcastReceiver;
Doris Liu6432cd62013-06-13 17:20:31 -070026import android.content.ContentResolver;
Michael Kolb08650182013-02-25 19:43:56 -080027import android.content.Context;
Michael Kolb8872c232013-01-29 10:33:22 -080028import android.content.Intent;
Doris Liub84b9732013-06-18 17:14:26 -070029import android.content.IntentFilter;
Sascha Haeberling2654dd92013-08-28 15:28:57 -070030import android.content.SharedPreferences;
Doris Liu3cf565c2013-02-15 10:55:37 -080031import android.content.pm.ActivityInfo;
Michael Kolb8872c232013-01-29 10:33:22 -080032import android.content.res.Configuration;
Angus Kong9f1db522013-11-09 16:25:59 -080033import android.graphics.Bitmap;
Erin Dahlgrenc120b0f2013-11-19 10:53:49 -080034import android.graphics.Color;
Doris Liu70da9182013-12-17 18:41:15 -080035import android.graphics.Matrix;
Angus Kong9f1db522013-11-09 16:25:59 -080036import android.graphics.SurfaceTexture;
Doris Liu6432cd62013-06-13 17:20:31 -070037import android.graphics.drawable.ColorDrawable;
38import android.net.Uri;
Mangesh Ghiwarea5682ab2013-09-19 09:24:23 -070039import android.nfc.NfcAdapter;
40import android.nfc.NfcAdapter.CreateBeamUrisCallback;
41import android.nfc.NfcEvent;
Mangesh Ghiwarea5682ab2013-09-19 09:24:23 -070042import android.os.Build;
Michael Kolb8872c232013-01-29 10:33:22 -080043import android.os.Bundle;
Doris Liu6432cd62013-06-13 17:20:31 -070044import android.os.Handler;
Doris Liuaa874422013-09-18 19:43:12 -070045import android.os.Looper;
46import android.os.Message;
Sascha Haeberling2654dd92013-08-28 15:28:57 -070047import android.preference.PreferenceManager;
Doris Liu2a7f44c2013-08-12 15:18:53 -070048import android.provider.MediaStore;
Doris Liu3cf565c2013-02-15 10:55:37 -080049import android.provider.Settings;
Sascha Haeberling37f36112013-08-06 14:31:52 -070050import android.util.Log;
Erin Dahlgrenc120b0f2013-11-19 10:53:49 -080051import android.view.Gravity;
Michael Kolb8872c232013-01-29 10:33:22 -080052import android.view.KeyEvent;
Doris Liu6432cd62013-06-13 17:20:31 -070053import android.view.LayoutInflater;
ztenghui0353ca22013-08-13 13:53:16 -070054import android.view.MenuItem;
Doris Liu742cd5b2013-09-12 16:17:43 -070055import android.view.MotionEvent;
Michael Kolb8872c232013-01-29 10:33:22 -080056import android.view.View;
Doris Liu6432cd62013-06-13 17:20:31 -070057import android.view.ViewGroup;
Michael Kolb08650182013-02-25 19:43:56 -080058import android.view.Window;
59import android.view.WindowManager;
Angus Kong653c43b2013-08-21 18:28:43 -070060import android.widget.FrameLayout;
Erin Dahlgrenc120b0f2013-11-19 10:53:49 -080061import android.widget.FrameLayout.LayoutParams;
Doris Liu6432cd62013-06-13 17:20:31 -070062import android.widget.ImageView;
Erin Dahlgrenc120b0f2013-11-19 10:53:49 -080063import android.widget.PopupWindow;
Sascha Haeberling37f36112013-08-06 14:31:52 -070064import android.widget.ProgressBar;
Mangesh Ghiwarecd2eeb02013-08-23 13:28:21 -070065import android.widget.ShareActionProvider;
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -080066import android.widget.TextView;
Michael Kolb8872c232013-01-29 10:33:22 -080067
Angus Kong9f1db522013-11-09 16:25:59 -080068import com.android.camera.app.AppController;
Doris Liuf55f3c42013-11-20 00:24:46 -080069import com.android.camera.app.CameraAppUI;
Angus Kong20fad242013-11-11 18:23:46 -080070import com.android.camera.app.CameraController;
71import com.android.camera.app.CameraManager;
72import com.android.camera.app.CameraManagerFactory;
73import com.android.camera.app.CameraProvider;
Angus Kongc4e66562013-11-22 23:03:21 -080074import com.android.camera.app.CameraServices;
Kevin Gabayanffbc43c2013-12-09 11:41:50 -080075import com.android.camera.app.LocationManager;
Angus Kong20fad242013-11-11 18:23:46 -080076import com.android.camera.app.ModuleManagerImpl;
Angus Kong9f1db522013-11-09 16:25:59 -080077import com.android.camera.app.OrientationManager;
78import com.android.camera.app.OrientationManagerImpl;
Doris Liu6432cd62013-06-13 17:20:31 -070079import com.android.camera.data.CameraDataAdapter;
Angus Kong8e5e4ee2013-07-30 11:36:00 -070080import com.android.camera.data.FixedLastDataAdapter;
Angus Kong32509872013-10-02 16:53:40 -070081import com.android.camera.data.InProgressDataWrapper;
Doris Liu6432cd62013-06-13 17:20:31 -070082import com.android.camera.data.LocalData;
Angus Kong8e5e4ee2013-07-30 11:36:00 -070083import com.android.camera.data.LocalDataAdapter;
ztenghui064d6002013-09-05 15:47:58 -070084import com.android.camera.data.LocalMediaObserver;
Angus Kong8a2350a2013-12-16 15:02:34 -080085import com.android.camera.data.PanoramaMetadataLoader;
86import com.android.camera.data.RgbzMetadataLoader;
Angus Kongbd260692013-08-07 14:52:56 -070087import com.android.camera.data.SimpleViewData;
Angus Kong01054e92013-12-10 11:06:18 -080088import com.android.camera.filmstrip.FilmstripContentPanel;
Angus Kong62848152013-11-08 17:25:29 -080089import com.android.camera.filmstrip.FilmstripController;
Angus Kong612321f2013-11-18 16:17:43 -080090import com.android.camera.module.ModulesInfo;
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -080091import com.android.camera.session.CaptureSessionManager;
92import com.android.camera.session.CaptureSessionManager.SessionListener;
93import com.android.camera.session.PlaceholderManager;
Erin Dahlgren357b7672013-11-20 17:38:14 -080094import com.android.camera.settings.SettingsManager;
95import com.android.camera.settings.SettingsManager.SettingsCapabilities;
Sascha Haeberlinga5a08d72013-09-11 20:30:52 -070096import com.android.camera.tinyplanet.TinyPlanetFragment;
Doris Liuf55f3c42013-11-20 00:24:46 -080097import com.android.camera.ui.MainActivityLayout;
Doris Liu1c94b7d2013-11-09 19:13:44 -080098import com.android.camera.ui.ModeListView;
Doris Liu06db7422013-12-09 19:36:25 -080099import com.android.camera.ui.PreviewStatusListener;
Erin Dahlgrenc120b0f2013-11-19 10:53:49 -0800100import com.android.camera.ui.SettingsView;
Sascha Haeberling88ef7662013-08-15 17:19:22 -0700101import com.android.camera.util.ApiHelper;
Angus Kongb50b5cb2013-08-09 14:55:20 -0700102import com.android.camera.util.CameraUtil;
Christian Wyglendowski6fe8c822013-11-26 14:16:04 -0800103import com.android.camera.util.FeedbackHelper;
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700104import com.android.camera.util.GcamHelper;
Alan Newberger761306f2013-10-30 12:51:21 -0700105import com.android.camera.util.IntentHelper;
Sascha Haeberling88ef7662013-08-15 17:19:22 -0700106import com.android.camera.util.PhotoSphereHelper.PanoramaViewHelper;
Seth Raphaelcbd82672013-11-05 10:12:36 -0800107import com.android.camera.util.UsageStatistics;
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800108import com.android.camera.widget.FilmstripView;
Sascha Haeberling8e963a52013-08-06 11:43:02 -0700109import com.android.camera2.R;
Michael Kolb8872c232013-01-29 10:33:22 -0800110
Seth Raphaelcbd82672013-11-05 10:12:36 -0800111import java.io.File;
Angus Konge2f4c032013-12-19 10:24:33 -0800112import java.util.List;
Seth Raphaelcbd82672013-11-05 10:12:36 -0800113
Doris Liu6432cd62013-06-13 17:20:31 -0700114public class CameraActivity extends Activity
Doris Liuf55f3c42013-11-20 00:24:46 -0800115 implements AppController, CameraManager.CameraOpenCallback,
Angus Kong9f1db522013-11-09 16:25:59 -0800116 ActionBar.OnMenuVisibilityListener, ShareActionProvider.OnShareTargetSelectedListener,
117 OrientationManager.OnOrientationChangeListener {
Doris Liu6432cd62013-06-13 17:20:31 -0700118
Sascha Haeberling58501152014-01-06 11:02:35 -0800119 private static final String TAG = "CameraActivity";
Doris Liu6432cd62013-06-13 17:20:31 -0700120
Doris Liu6432cd62013-06-13 17:20:31 -0700121 private static final String INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE =
122 "android.media.action.STILL_IMAGE_CAMERA_SECURE";
123 public static final String ACTION_IMAGE_CAPTURE_SECURE =
124 "android.media.action.IMAGE_CAPTURE_SECURE";
125
126 // The intent extra for camera from secure lock screen. True if the gallery
127 // should only show newly captured pictures. sSecureAlbumId does not
128 // increment. This is used when switching between camera, camcorder, and
129 // panorama. If the extra is not set, it is in the normal camera mode.
130 public static final String SECURE_CAMERA_EXTRA = "secure_camera";
131
Sascha Haeberlingb7639c62013-09-09 14:42:43 -0700132 /**
Angus Kong20fad242013-11-11 18:23:46 -0800133 * Request code from an activity we started that indicated that we do not want
134 * to reset the view to the preview in onResume.
Sascha Haeberlingb7639c62013-09-09 14:42:43 -0700135 */
136 public static final int REQ_CODE_DONT_SWITCH_TO_PREVIEW = 142;
137
Ruben Brunkd217ed02013-10-08 23:31:13 -0700138 public static final int REQ_CODE_GCAM_DEBUG_POSTCAPTURE = 999;
139
Angus Kong13e87c42013-11-25 10:02:47 -0800140 private static final int MSG_HIDE_ACTION_BAR = 1;
141 private static final int MSG_CLEAR_SCREEN_ON_FLAG = 2;
Angus Kong13e87c42013-11-25 10:02:47 -0800142 private static final long SCREEN_DELAY_MS = 2 * 60 * 1000; // 2 mins.
Doris Liuaa874422013-09-18 19:43:12 -0700143
Angus Kong20fad242013-11-11 18:23:46 -0800144 /**
145 * Whether onResume should reset the view to the preview.
146 */
Sascha Haeberlingb7639c62013-09-09 14:42:43 -0700147 private boolean mResetToPreviewOnResume = true;
148
Angus Kong20fad242013-11-11 18:23:46 -0800149 /**
150 * This data adapter is used by FilmStripView.
151 */
Angus Kong8e5e4ee2013-07-30 11:36:00 -0700152 private LocalDataAdapter mDataAdapter;
Angus Kong8e5e4ee2013-07-30 11:36:00 -0700153
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800154 /**
155 * TODO: This should be moved to the app level.
156 */
Erin Dahlgrenc120b0f2013-11-19 10:53:49 -0800157 private SettingsManager mSettingsManager;
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800158
159 /**
160 * TODO: This should be moved to the app level.
161 */
Erin Dahlgren357b7672013-11-20 17:38:14 -0800162 private SettingsController mSettingsController;
Doris Liu70576b62013-11-14 20:30:33 -0800163 private ModeListView mModeListView;
Erin Dahlgrenc120b0f2013-11-19 10:53:49 -0800164 private int mCurrentModeIndex;
Doris Liu6432cd62013-06-13 17:20:31 -0700165 private CameraModule mCurrentModule;
Angus Kong20fad242013-11-11 18:23:46 -0800166 private ModuleManagerImpl mModuleManager;
Angus Kong653c43b2013-08-21 18:28:43 -0700167 private FrameLayout mAboveFilmstripControlLayout;
Angus Kong62848152013-11-08 17:25:29 -0800168 private FilmstripController mFilmstripController;
Angus Kongfaaee012013-12-07 00:38:46 -0800169 private boolean mFilmstripVisible;
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800170 private TextView mBottomProgressText;
171 private ProgressBar mBottomProgressBar;
172 private View mSessionProgressPanel;
Doris Liu6432cd62013-06-13 17:20:31 -0700173 private int mResultCodeForTesting;
174 private Intent mResultDataForTesting;
175 private OnScreenHint mStorageHint;
Angus Kong2dcc0a92013-09-25 13:00:08 -0700176 private long mStorageSpaceBytes = Storage.LOW_STORAGE_THRESHOLD_BYTES;
Doris Liu3cf565c2013-02-15 10:55:37 -0800177 private boolean mAutoRotateScreen;
Doris Liu6432cd62013-06-13 17:20:31 -0700178 private boolean mSecureCamera;
Doris Liu6432cd62013-06-13 17:20:31 -0700179 private int mLastRawOrientation;
Angus Kong9f1db522013-11-09 16:25:59 -0800180 private OrientationManagerImpl mOrientationManager;
Erin Dahlgren21c21a62013-11-19 16:37:38 -0800181 private LocationManager mLocationManager;
Erin Dahlgren8a2933b2013-12-06 12:07:33 -0800182 private ButtonManager mButtonManager;
Doris Liu6432cd62013-06-13 17:20:31 -0700183 private Handler mMainHandler;
Sascha Haeberlingf1f51862013-07-31 11:28:21 -0700184 private PanoramaViewHelper mPanoramaViewHelper;
ztenghuifa9e2cc2013-08-09 17:37:15 -0700185 private ActionBar mActionBar;
Angus Kong653c43b2013-08-21 18:28:43 -0700186 private ViewGroup mUndoDeletionBar;
Doris Liu742cd5b2013-09-12 16:17:43 -0700187 private boolean mIsUndoingDeletion = false;
Doris Liu3cf565c2013-02-15 10:55:37 -0800188
Sascha Haeberling280fd3e2013-11-21 13:52:15 -0800189 private final Uri[] mNfcPushUris = new Uri[1];
Mangesh Ghiwarea5682ab2013-09-19 09:24:23 -0700190
ztenghui064d6002013-09-05 15:47:58 -0700191 private LocalMediaObserver mLocalImagesObserver;
192 private LocalMediaObserver mLocalVideosObserver;
Mangesh Ghiwarecd2eeb02013-08-23 13:28:21 -0700193
Doris Liu742cd5b2013-09-12 16:17:43 -0700194 private boolean mPendingDeletion = false;
Sascha Haeberling5199c202013-09-05 17:10:19 -0700195
Angus Kong20fad242013-11-11 18:23:46 -0800196 private CameraController mCameraController;
Erin Dahlgrenc120b0f2013-11-19 10:53:49 -0800197 private boolean mPaused;
Doris Liuf55f3c42013-11-20 00:24:46 -0800198 private CameraAppUI mCameraAppUI;
Angus Kong20fad242013-11-11 18:23:46 -0800199
Christian Wyglendowski6fe8c822013-11-26 14:16:04 -0800200 private FeedbackHelper mFeedbackHelper;
201
Spike Sprague0f3c4b42013-12-10 19:50:17 -0800202 @Override
203 public CameraAppUI getCameraAppUI() {
204 return mCameraAppUI;
205 }
206
Doris Liub84b9732013-06-18 17:14:26 -0700207 // close activity when screen turns off
Sascha Haeberling280fd3e2013-11-21 13:52:15 -0800208 private final BroadcastReceiver mScreenOffReceiver = new BroadcastReceiver() {
Doris Liub84b9732013-06-18 17:14:26 -0700209 @Override
210 public void onReceive(Context context, Intent intent) {
211 finish();
212 }
213 };
214
Angus Kong13e87c42013-11-25 10:02:47 -0800215 /**
216 * Whether the screen is kept turned on.
217 */
218 private boolean mKeepScreenOn;
Angus Kong53ae0412013-12-01 23:21:49 -0800219 private int mLastLayoutOrientation;
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800220 private final CameraAppUI.BottomControls.Listener mMyFilmstripBottomControlListener =
Angus Kongb2510252013-12-10 22:58:15 -0800221 new CameraAppUI.BottomControls.Listener() {
222
223 /**
224 * If the current photo is a photo sphere, this will launch the Photo Sphere
225 * panorama viewer.
226 */
227 @Override
Angus Kong8a2350a2013-12-16 15:02:34 -0800228 public void onExternalViewer() {
229 if (mPanoramaViewHelper == null) {
230 return;
231 }
232 final LocalData data = getCurrentLocalData();
233 if (data == null) {
234 return;
235 }
236 final Uri contentUri = data.getContentUri();
237 if (contentUri == Uri.EMPTY) {
238 return;
239 }
240
241 if (PanoramaMetadataLoader.isPanorama(data)) {
242 mPanoramaViewHelper.showPanorama(contentUri);
243 } else if (RgbzMetadataLoader.hasRGBZData(data)) {
244 mPanoramaViewHelper.showRgbz(contentUri);
Angus Kongb2510252013-12-10 22:58:15 -0800245 }
246 }
247
248 @Override
249 public void onEdit() {
250 LocalData data = getCurrentLocalData();
251 if (data == null) {
252 return;
253 }
254 launchEditor(data);
255 }
256
257 @Override
258 public void onTinyPlanet() {
259 LocalData data = getCurrentLocalData();
260 if (data == null) {
261 return;
262 }
Angus Konge0aff892013-12-11 20:51:01 -0800263 final int currentDataId = getCurrentDataId();
264 UsageStatistics.onEvent(UsageStatistics.COMPONENT_CAMERA,
265 UsageStatistics.ACTION_EDIT, null, 0,
266 UsageStatistics.hashFileName(fileNameFromDataID(currentDataId)));
Angus Kongb2510252013-12-10 22:58:15 -0800267 launchTinyPlanetEditor(data);
268 }
269
Angus Konge0aff892013-12-11 20:51:01 -0800270 @Override
271 public void onDelete() {
272 final int currentDataId = getCurrentDataId();
273 UsageStatistics.onEvent(UsageStatistics.COMPONENT_CAMERA,
274 UsageStatistics.ACTION_DELETE, null, 0,
275 UsageStatistics.hashFileName(fileNameFromDataID(currentDataId)));
276 removeData(currentDataId);
277 }
278
279 @Override
280 public void onShare() {
Angus Kong662fbf42013-12-12 13:22:03 -0800281 final LocalData data = getCurrentLocalData();
282 Intent shareIntent = getShareIntentByData(data);
283 if (shareIntent != null) {
Angus Konge4002f32013-12-13 22:24:11 -0800284 try {
Angus Kong0eaf0162013-12-16 15:53:30 -0800285 launchActivityByIntent(shareIntent);
Angus Konge4002f32013-12-13 22:24:11 -0800286 mCameraAppUI.getFilmstripBottomControls().setShareEnabled(false);
287 } catch (ActivityNotFoundException ex) {
288 // Nothing.
289 }
Angus Kong662fbf42013-12-12 13:22:03 -0800290 }
Angus Konge0aff892013-12-11 20:51:01 -0800291 }
292
293 @Override
294 public void onGallery() {
Angus Kongd3de1712013-12-12 22:01:12 -0800295 startGallery();
Angus Konge0aff892013-12-11 20:51:01 -0800296 }
297
298 private int getCurrentDataId() {
299 return mFilmstripController.getCurrentId();
300 }
301
Angus Kongb2510252013-12-10 22:58:15 -0800302 private LocalData getCurrentLocalData() {
Angus Konge0aff892013-12-11 20:51:01 -0800303 return mDataAdapter.getLocalData(getCurrentDataId());
Angus Kongb2510252013-12-10 22:58:15 -0800304 }
Angus Kong662fbf42013-12-12 13:22:03 -0800305
306 /**
307 * Sets up the share intent and NFC properly according to the data.
308 *
309 * @param data The data to be shared.
310 */
311 private Intent getShareIntentByData(final LocalData data) {
312 Intent intent = null;
313 final Uri contentUri = data.getContentUri();
Angus Kong8a2350a2013-12-16 15:02:34 -0800314 if (PanoramaMetadataLoader.isPanorama360(data) &&
Angus Kong662fbf42013-12-12 13:22:03 -0800315 data.getContentUri() != Uri.EMPTY) {
316 intent = new Intent(Intent.ACTION_SEND);
317 intent.setType("application/vnd.google.panorama360+jpg");
318 intent.putExtra(Intent.EXTRA_STREAM, contentUri);
319 } else if (data.isDataActionSupported(LocalData.DATA_ACTION_SHARE)) {
320 final String mimeType = data.getMimeType();
321 intent = getShareIntentFromType(mimeType);
322 if (intent != null) {
323 intent.putExtra(Intent.EXTRA_STREAM, contentUri);
324 intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
325 }
326 }
327 return intent;
328 }
329
330 /**
331 * Get the share intent according to the mimeType
332 *
333 * @param mimeType The mimeType of current data.
334 * @return the video/image's ShareIntent or null if mimeType is invalid.
335 */
336 private Intent getShareIntentFromType(String mimeType) {
337 // Lazily create the intent object.
338 Intent intent = new Intent(Intent.ACTION_SEND);
339 if (mimeType.startsWith("video/")) {
340 intent.setType("video/*");
341 } else {
342 if (mimeType.startsWith("image/")) {
343 intent.setType("image/*");
344 } else {
345 Log.w(TAG, "unsupported mimeType " + mimeType);
346 }
347 }
348 return intent;
349 }
Angus Kongb2510252013-12-10 22:58:15 -0800350 };
Angus Kong13e87c42013-11-25 10:02:47 -0800351
Kevin Gabayanffbc43c2013-12-09 11:41:50 -0800352 private ComboPreferences mPreferences;
353 private ContentResolver mContentResolver;
354
Angus Kong20fad242013-11-11 18:23:46 -0800355 @Override
356 public void onCameraOpened(CameraManager.CameraProxy camera) {
Erin Dahlgrenc120b0f2013-11-19 10:53:49 -0800357 if (!mModuleManager.getModuleAgent(mCurrentModeIndex).requestAppForCamera()) {
Angus Kong20fad242013-11-11 18:23:46 -0800358 // We shouldn't be here. Just close the camera and leave.
359 camera.release(false);
360 throw new IllegalStateException("Camera opened but the module shouldn't be " +
361 "requesting");
362 }
Angus Kong13e87c42013-11-25 10:02:47 -0800363 if (mCurrentModule != null) {
Erin Dahlgren357b7672013-11-20 17:38:14 -0800364 SettingsCapabilities capabilities =
365 SettingsController.getSettingsCapabilities(camera);
366 mSettingsManager.changeCamera(camera.getCameraId(), capabilities);
Angus Kong13e87c42013-11-25 10:02:47 -0800367 mCurrentModule.onCameraAvailable(camera);
Angus Kong20fad242013-11-11 18:23:46 -0800368 }
Erin Dahlgren1648c362014-01-06 15:06:04 -0800369 mCameraAppUI.onChangeCamera();
Angus Kong20fad242013-11-11 18:23:46 -0800370 }
371
372 @Override
373 public void onCameraDisabled(int cameraId) {
374 UsageStatistics.onEvent(UsageStatistics.COMPONENT_CAMERA, UsageStatistics.ACTION_OPEN_FAIL,
375 "security");
376
377 CameraUtil.showErrorAndFinish(this, R.string.camera_disabled);
378 }
379
380 @Override
381 public void onDeviceOpenFailure(int cameraId) {
382 UsageStatistics.onEvent(UsageStatistics.COMPONENT_CAMERA,
383 UsageStatistics.ACTION_OPEN_FAIL, "open");
384
385 CameraUtil.showErrorAndFinish(this, R.string.cannot_connect_camera);
386 }
387
388 @Override
389 public void onReconnectionFailure(CameraManager mgr) {
390 UsageStatistics.onEvent(UsageStatistics.COMPONENT_CAMERA,
391 UsageStatistics.ACTION_OPEN_FAIL, "reconnect");
392
393 CameraUtil.showErrorAndFinish(this, R.string.cannot_connect_camera);
394 }
395
Doris Liuaa874422013-09-18 19:43:12 -0700396 private class MainHandler extends Handler {
397 public MainHandler(Looper looper) {
398 super(looper);
399 }
400
401 @Override
402 public void handleMessage(Message msg) {
Angus Kong13e87c42013-11-25 10:02:47 -0800403 switch (msg.what) {
404 case MSG_HIDE_ACTION_BAR: {
405 removeMessages(MSG_HIDE_ACTION_BAR);
Angus Kongb2510252013-12-10 22:58:15 -0800406 CameraActivity.this.setFilmstripUiVisibility(false);
Angus Kong13e87c42013-11-25 10:02:47 -0800407 break;
408 }
409
410 case MSG_CLEAR_SCREEN_ON_FLAG: {
411 if (!mPaused) {
412 getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
413 }
414 break;
415 }
416
417 default:
Doris Liuaa874422013-09-18 19:43:12 -0700418 }
419 }
420 }
421
Seth Raphaelcbd82672013-11-05 10:12:36 -0800422 private String fileNameFromDataID(int dataID) {
423 final LocalData localData = mDataAdapter.getLocalData(dataID);
424
425 File localFile = new File(localData.getPath());
426 return localFile.getName();
427 }
428
Angus Kong01054e92013-12-10 11:06:18 -0800429 private final FilmstripContentPanel.Listener mFilmstripListener =
430 new FilmstripContentPanel.Listener() {
Angus Kongfaaee012013-12-07 00:38:46 -0800431
432 @Override
433 public void onFilmstripHidden() {
434 mFilmstripVisible = false;
Angus Kongb2510252013-12-10 22:58:15 -0800435 CameraActivity.this.setFilmstripUiVisibility(false);
Angus Kongfaaee012013-12-07 00:38:46 -0800436 // When the user hide the filmstrip (either swipe out or
437 // tap on back key) we move to the first item so next time
438 // when the user swipe in the filmstrip, the most recent
439 // one is shown.
440 mFilmstripController.goToFirstItem();
441 if (mCurrentModule != null) {
442 mCurrentModule.onPreviewVisibilityChanged(true);
443 }
444 }
445
446 @Override
447 public void onFilmstripShown() {
448 mFilmstripVisible = true;
449 updateUiByData(mFilmstripController.getCurrentId());
450 if (mCurrentModule != null) {
451 mCurrentModule.onPreviewVisibilityChanged(false);
452 }
453 }
454
Sascha Haeberling37f36112013-08-06 14:31:52 -0700455 @Override
456 public void onDataPromoted(int dataID) {
Seth Raphaelcbd82672013-11-05 10:12:36 -0800457 UsageStatistics.onEvent(UsageStatistics.COMPONENT_CAMERA,
458 UsageStatistics.ACTION_DELETE, "promoted", 0,
459 UsageStatistics.hashFileName(fileNameFromDataID(dataID)));
460
Sascha Haeberling37f36112013-08-06 14:31:52 -0700461 removeData(dataID);
462 }
Doris Liu6432cd62013-06-13 17:20:31 -0700463
Sascha Haeberling37f36112013-08-06 14:31:52 -0700464 @Override
465 public void onDataDemoted(int dataID) {
Seth Raphaelcbd82672013-11-05 10:12:36 -0800466 UsageStatistics.onEvent(UsageStatistics.COMPONENT_CAMERA,
467 UsageStatistics.ACTION_DELETE, "demoted", 0,
468 UsageStatistics.hashFileName(fileNameFromDataID(dataID)));
469
Sascha Haeberling37f36112013-08-06 14:31:52 -0700470 removeData(dataID);
471 }
Doris Liu6432cd62013-06-13 17:20:31 -0700472
Sascha Haeberling37f36112013-08-06 14:31:52 -0700473 @Override
Angus Kongfaaee012013-12-07 00:38:46 -0800474 public void onEnterFullScreen(int dataId) {
475 if (mFilmstripVisible) {
Angus Kongb2510252013-12-10 22:58:15 -0800476 CameraActivity.this.setFilmstripUiVisibility(false);
Erin Dahlgren3044d8c2013-10-10 18:23:45 -0700477 }
478 }
479
480 @Override
Angus Kongfaaee012013-12-07 00:38:46 -0800481 public void onLeaveFullScreen(int dataId) {
482 // Do nothing.
483 }
Erin Dahlgren3044d8c2013-10-10 18:23:45 -0700484
Angus Kongfaaee012013-12-07 00:38:46 -0800485 @Override
486 public void onEnterFilmstrip(int dataId) {
487 if (mFilmstripVisible) {
Angus Kongb2510252013-12-10 22:58:15 -0800488 CameraActivity.this.setFilmstripUiVisibility(true);
Erin Dahlgren3044d8c2013-10-10 18:23:45 -0700489 }
490 }
491
492 @Override
Angus Kongfaaee012013-12-07 00:38:46 -0800493 public void onLeaveFilmstrip(int dataId) {
494 // Do nothing.
495 }
496
497 @Override
498 public void onDataReloaded() {
499 if (!mFilmstripVisible) {
500 return;
501 }
502 updateUiByData(mFilmstripController.getCurrentId());
503 }
504
505 @Override
Angus Kong8a2350a2013-12-16 15:02:34 -0800506 public void onDataUpdated(int dataId) {
507 if (!mFilmstripVisible) {
508 return;
509 }
510 updateUiByData(mFilmstripController.getCurrentId());
511 }
512
513 @Override
Angus Kongfaaee012013-12-07 00:38:46 -0800514 public void onEnterZoomView(int dataID) {
515 if (mFilmstripVisible) {
Angus Kongb2510252013-12-10 22:58:15 -0800516 CameraActivity.this.setFilmstripUiVisibility(false);
Angus Kongfaaee012013-12-07 00:38:46 -0800517 }
518 }
519
520 @Override
521 public void onDataFocusChanged(final int prevDataId, final int newDataId) {
522 if (!mFilmstripVisible) {
523 return;
Doris Liuaa874422013-09-18 19:43:12 -0700524 }
Angus Kong02cafdf2013-10-13 19:26:02 -0700525 // TODO: This callback is UI event callback, should always
526 // happen on UI thread. Find the reason for this
527 // runOnUiThread() and fix it.
Mangesh Ghiware33035c12013-08-23 13:28:21 -0700528 runOnUiThread(new Runnable() {
529 @Override
530 public void run() {
Angus Kongfaaee012013-12-07 00:38:46 -0800531 updateUiByData(newDataId);
ztenghui2c3d9a52013-09-03 11:27:21 -0700532 }
Mangesh Ghiware33035c12013-08-23 13:28:21 -0700533 });
Sascha Haeberling37f36112013-08-06 14:31:52 -0700534 }
535 };
536
Sascha Haeberling44c1afb2013-12-20 11:59:35 -0800537 private final LocalDataAdapter.LocalDataListener mLocalDataListener =
Angus Konge2f4c032013-12-19 10:24:33 -0800538 new LocalDataAdapter.LocalDataListener() {
539 @Override
540 public void onMetadataUpdated(List<Integer> updatedData) {
541 int currentDataId = mFilmstripController.getCurrentId();
542 for (Integer dataId : updatedData) {
543 if (dataId == currentDataId) {
544 updateBottomControlsByData(mDataAdapter.getLocalData(dataId));
545 }
546 }
547 }
548 };
549
Sascha Haeberling4ed20592013-09-13 11:58:33 -0700550 public void gotoGallery() {
Seth Raphaelcbd82672013-11-05 10:12:36 -0800551 UsageStatistics.onEvent(UsageStatistics.COMPONENT_CAMERA, UsageStatistics.ACTION_FILMSTRIP,
552 "thumbnailTap");
553
Angus Kong62848152013-11-08 17:25:29 -0800554 mFilmstripController.goToNextItem();
Sascha Haeberling4ed20592013-09-13 11:58:33 -0700555 }
556
Sascha Haeberling5199c202013-09-05 17:10:19 -0700557 /**
Angus Kongfaaee012013-12-07 00:38:46 -0800558 * If {@param visible} is false, this hides the action bar and switches the
Angus Kongb2510252013-12-10 22:58:15 -0800559 * filmstrip UI to lights-out mode.
Sascha Haeberling5199c202013-09-05 17:10:19 -0700560 */
Doris Liu97cb1ea2013-10-11 16:54:51 -0700561 // TODO: This should not be called outside of the activity.
Angus Kongb2510252013-12-10 22:58:15 -0800562 public void setFilmstripUiVisibility(boolean visible) {
Angus Kong13e87c42013-11-25 10:02:47 -0800563 mMainHandler.removeMessages(MSG_HIDE_ACTION_BAR);
Doris Liuaa874422013-09-18 19:43:12 -0700564
ztenghui17f1e652013-11-06 14:20:31 -0800565 int currentSystemUIVisibility = mAboveFilmstripControlLayout.getSystemUiVisibility();
Doris Liu773e1c92013-12-02 17:35:03 -0800566 int newSystemUIVisibility = (visible ? View.SYSTEM_UI_FLAG_VISIBLE :
ztenghui17f1e652013-11-06 14:20:31 -0800567 View.SYSTEM_UI_FLAG_LOW_PROFILE | View.SYSTEM_UI_FLAG_FULLSCREEN);
568 if (newSystemUIVisibility != currentSystemUIVisibility) {
569 mAboveFilmstripControlLayout.setSystemUiVisibility(newSystemUIVisibility);
570 }
Doris Liu97cb1ea2013-10-11 16:54:51 -0700571
ztenghui17f1e652013-11-06 14:20:31 -0800572 boolean currentActionBarVisibility = mActionBar.isShowing();
Angus Kongb2510252013-12-10 22:58:15 -0800573 mCameraAppUI.getFilmstripBottomControls().setVisible(visible);
ztenghui17f1e652013-11-06 14:20:31 -0800574 if (visible != currentActionBarVisibility) {
Doris Liuaa874422013-09-18 19:43:12 -0700575 if (visible) {
576 mActionBar.show();
577 } else {
578 mActionBar.hide();
579 }
Doris Liuaa874422013-09-18 19:43:12 -0700580 }
Sascha Haeberling5199c202013-09-05 17:10:19 -0700581 }
582
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800583 private void hideSessionProgress() {
584 mSessionProgressPanel.setVisibility(View.GONE);
Sascha Haeberling37f36112013-08-06 14:31:52 -0700585 }
586
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800587 private void showSessionProgress(CharSequence message) {
588 mBottomProgressText.setText(message);
589 mSessionProgressPanel.setVisibility(View.VISIBLE);
Sascha Haeberling37f36112013-08-06 14:31:52 -0700590 }
591
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800592 private void updateSessionProgress(int progress) {
593 mBottomProgressBar.setProgress(progress);
Sascha Haeberling37f36112013-08-06 14:31:52 -0700594 }
Doris Liu6432cd62013-06-13 17:20:31 -0700595
Mangesh Ghiwarea5682ab2013-09-19 09:24:23 -0700596 @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
597 private void setupNfcBeamPush() {
598 NfcAdapter adapter = NfcAdapter.getDefaultAdapter(CameraActivity.this);
599 if (adapter == null) {
600 return;
601 }
602
603 if (!ApiHelper.HAS_SET_BEAM_PUSH_URIS) {
604 // Disable beaming
605 adapter.setNdefPushMessage(null, CameraActivity.this);
606 return;
607 }
608
609 adapter.setBeamPushUris(null, CameraActivity.this);
610 adapter.setBeamPushUrisCallback(new CreateBeamUrisCallback() {
611 @Override
612 public Uri[] createBeamUris(NfcEvent event) {
613 return mNfcPushUris;
614 }
615 }, CameraActivity.this);
616 }
617
Doris Liuaa874422013-09-18 19:43:12 -0700618 @Override
619 public void onMenuVisibilityChanged(boolean isVisible) {
Angus Kongfaaee012013-12-07 00:38:46 -0800620 // TODO: Remove this or bring back the original implementation: cancel
621 // auto-hide actionbar.
Doris Liuaa874422013-09-18 19:43:12 -0700622 }
623
Seth Raphaelcbd82672013-11-05 10:12:36 -0800624 @Override
625 public boolean onShareTargetSelected(ShareActionProvider shareActionProvider, Intent intent) {
Angus Kong62848152013-11-08 17:25:29 -0800626 int currentDataId = mFilmstripController.getCurrentId();
Seth Raphaelcbd82672013-11-05 10:12:36 -0800627 if (currentDataId < 0) {
628 return false;
629 }
630 UsageStatistics.onEvent(UsageStatistics.COMPONENT_CAMERA, UsageStatistics.ACTION_SHARE,
631 intent.getComponent().getPackageName(), 0,
632 UsageStatistics.hashFileName(fileNameFromDataID(currentDataId)));
633 return true;
634 }
635
Sascha Haeberling14ff6c82013-12-13 13:29:58 -0800636 // Note: All callbacks come back on the main thread.
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800637 private final SessionListener mSessionListener =
638 new SessionListener() {
Ruben Brunk7cfcafd2013-10-17 15:41:44 -0700639 @Override
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800640 public void onSessionQueued(final Uri uri) {
Sascha Haeberling14ff6c82013-12-13 13:29:58 -0800641 notifyNewMedia(uri);
642 int dataID = mDataAdapter.findDataByContentUri(uri);
643 if (dataID != -1) {
644 // Don't allow special UI actions (swipe to
645 // delete, for example) on in-progress data.
646 LocalData d = mDataAdapter.getLocalData(dataID);
647 InProgressDataWrapper newData = new InProgressDataWrapper(d);
648 mDataAdapter.updateData(dataID, newData);
649 }
Angus Kong6798c342013-07-16 15:14:58 -0700650 }
651
652 @Override
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800653 public void onSessionDone(final Uri uri) {
654 Log.v(TAG, "onSessionDone:" + uri);
Sascha Haeberling14ff6c82013-12-13 13:29:58 -0800655 int doneID = mDataAdapter.findDataByContentUri(uri);
656 int currentDataId = mFilmstripController.getCurrentId();
Sascha Haeberling37f36112013-08-06 14:31:52 -0700657
Sascha Haeberling14ff6c82013-12-13 13:29:58 -0800658 if (currentDataId == doneID) {
659 hideSessionProgress();
660 updateSessionProgress(0);
661 }
Sascha Haeberling44c1afb2013-12-20 11:59:35 -0800662 mDataAdapter.refresh(uri, /* isInProgress */ false);
Angus Kong6798c342013-07-16 15:14:58 -0700663 }
664
665 @Override
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800666 public void onSessionProgress(final Uri uri, final int progress) {
667 if (progress < 0) {
668 // Do nothing, there is no task for this URI.
669 return;
670 }
Sascha Haeberling14ff6c82013-12-13 13:29:58 -0800671 int currentDataId = mFilmstripController.getCurrentId();
672 if (currentDataId == -1) {
673 return;
674 }
675 if (uri.equals(
676 mDataAdapter.getLocalData(currentDataId).getContentUri())) {
677 updateSessionProgress(progress);
678 }
679 }
680
681 @Override
682 public void onSessionUpdated(Uri uri) {
Sascha Haeberling44c1afb2013-12-20 11:59:35 -0800683 mDataAdapter.refresh(uri, /* isInProgress */ true);
Angus Kong6798c342013-07-16 15:14:58 -0700684 }
685 };
686
Angus Kong9f1db522013-11-09 16:25:59 -0800687 @Override
688 public Context getAndroidContext() {
689 return this;
690 }
691
692 @Override
Angus Kong0eaf0162013-12-16 15:53:30 -0800693 public void launchActivityByIntent(Intent intent) {
694 startActivityForResult(intent, REQ_CODE_DONT_SWITCH_TO_PREVIEW);
695 }
696
697 @Override
Doris Liuf55f3c42013-11-20 00:24:46 -0800698 public int getCurrentModuleIndex() {
699 return mCurrentModeIndex;
700 }
701
702 @Override
Angus Kong9f1db522013-11-09 16:25:59 -0800703 public SurfaceTexture getPreviewBuffer() {
704 // TODO: implement this
705 return null;
706 }
707
708 @Override
Doris Liu2b906b82013-12-10 16:34:08 -0800709 public void onPreviewStarted() {
710 mCameraAppUI.onPreviewStarted();
711 }
712
713 @Override
Doris Liu482de022013-12-18 19:18:16 -0800714 public void addPreviewAreaSizeChangedListener(
715 PreviewStatusListener.PreviewAreaSizeChangedListener listener) {
716 mCameraAppUI.addPreviewAreaSizeChangedListener(listener);
717 }
718
719 @Override
720 public void removePreviewAreaSizeChangedListener(
721 PreviewStatusListener.PreviewAreaSizeChangedListener listener) {
722 mCameraAppUI.removePreviewAreaSizeChangedListener(listener);
723 }
724
725 @Override
Doris Liu4d4a4bc2013-12-19 18:55:54 -0800726 public void setupOneShotPreviewListener() {
727 mCameraController.setOneShotPreviewCallback(mMainHandler,
728 new CameraManager.CameraPreviewDataCallback() {
Doris Liu482de022013-12-18 19:18:16 -0800729 @Override
730 public void onPreviewFrame(byte[] data, CameraManager.CameraProxy camera) {
731 mCameraAppUI.onNewPreviewFrame();
732 }
733 });
Doris Liu4d4a4bc2013-12-19 18:55:54 -0800734 }
735
736 @Override
Doris Liu70da9182013-12-17 18:41:15 -0800737 public void updatePreviewAspectRatio(float aspectRatio) {
738 mCameraAppUI.updatePreviewAspectRatio(aspectRatio);
739 }
740
741 @Override
742 public void updatePreviewTransform(Matrix matrix) {
743 mCameraAppUI.updatePreviewTransform(matrix);
744 }
745
746 @Override
Doris Liu06db7422013-12-09 19:36:25 -0800747 public void setPreviewStatusListener(PreviewStatusListener previewStatusListener) {
748 mCameraAppUI.setPreviewStatusListener(previewStatusListener);
749 }
750
751 @Override
Angus Kong9f1db522013-11-09 16:25:59 -0800752 public FrameLayout getModuleLayoutRoot() {
Doris Liuc6c97402013-12-06 21:02:53 -0800753 return mCameraAppUI.getModuleRootView();
Angus Kong9f1db522013-11-09 16:25:59 -0800754 }
755
756 @Override
757 public void setShutterEventsListener(ShutterEventsListener listener) {
758 // TODO: implement this
759 }
760
761 @Override
762 public void setShutterEnabled(boolean enabled) {
763 // TODO: implement this
764 }
765
766 @Override
767 public boolean isShutterEnabled() {
768 // TODO: implement this
769 return false;
770 }
771
772 @Override
773 public void startPreCaptureAnimation() {
Doris Liu1dfe7822013-12-12 00:02:08 -0800774 mCameraAppUI.startPreCaptureAnimation();
Angus Kong9f1db522013-11-09 16:25:59 -0800775 }
776
777 @Override
778 public void cancelPreCaptureAnimation() {
779 // TODO: implement this
780 }
781
782 @Override
783 public void startPostCaptureAnimation() {
784 // TODO: implement this
785 }
786
787 @Override
788 public void startPostCaptureAnimation(Bitmap thumbnail) {
789 // TODO: implement this
790 }
791
792 @Override
793 public void cancelPostCaptureAnimation() {
794 // TODO: implement this
795 }
796
797 @Override
Angus Kong9f1db522013-11-09 16:25:59 -0800798 public OrientationManager getOrientationManager() {
799 return mOrientationManager;
800 }
801
802 @Override
803 public LocationManager getLocationManager() {
Erin Dahlgren21c21a62013-11-19 16:37:38 -0800804 return mLocationManager;
Angus Kong9f1db522013-11-09 16:25:59 -0800805 }
806
807 @Override
808 public void lockOrientation() {
809 mOrientationManager.lockOrientation();
810 }
811
812 @Override
813 public void unlockOrientation() {
814 mOrientationManager.unlockOrientation();
815 }
816
817 @Override
Doris Liu6432cd62013-06-13 17:20:31 -0700818 public void notifyNewMedia(Uri uri) {
819 ContentResolver cr = getContentResolver();
820 String mimeType = cr.getType(uri);
821 if (mimeType.startsWith("video/")) {
Angus Kongb50b5cb2013-08-09 14:55:20 -0700822 sendBroadcast(new Intent(CameraUtil.ACTION_NEW_VIDEO, uri));
Sascha Haeberling44c1afb2013-12-20 11:59:35 -0800823 mDataAdapter.addNewVideo(uri);
Doris Liu6432cd62013-06-13 17:20:31 -0700824 } else if (mimeType.startsWith("image/")) {
Angus Kongb50b5cb2013-08-09 14:55:20 -0700825 CameraUtil.broadcastNewPicture(this, uri);
Sascha Haeberling44c1afb2013-12-20 11:59:35 -0800826 mDataAdapter.addNewPhoto(uri);
Ruben Brunk7cfcafd2013-10-17 15:41:44 -0700827 } else if (mimeType.startsWith(PlaceholderManager.PLACEHOLDER_MIME_TYPE)) {
Sascha Haeberling44c1afb2013-12-20 11:59:35 -0800828 mDataAdapter.addNewPhoto(uri);
Doris Liu48239f42013-03-04 22:19:10 -0800829 } else {
Doris Liu6432cd62013-06-13 17:20:31 -0700830 android.util.Log.w(TAG, "Unknown new media with MIME type:"
831 + mimeType + ", uri:" + uri);
Doris Liu48239f42013-03-04 22:19:10 -0800832 }
833 }
834
Angus Kong20fad242013-11-11 18:23:46 -0800835 @Override
Angus Kong13e87c42013-11-25 10:02:47 -0800836 public void enableKeepScreenOn(boolean enabled) {
837 if (mPaused) {
838 return;
839 }
840
841 mKeepScreenOn = enabled;
842 if (mKeepScreenOn) {
843 mMainHandler.removeMessages(MSG_CLEAR_SCREEN_ON_FLAG);
844 getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
845 } else {
846 keepScreenOnForAWhile();
847 }
848 }
849
850 @Override
Angus Kong20fad242013-11-11 18:23:46 -0800851 public CameraProvider getCameraProvider() {
852 return mCameraController;
853 }
854
Doris Liu6432cd62013-06-13 17:20:31 -0700855 private void removeData(int dataID) {
Sascha Haeberling44c1afb2013-12-20 11:59:35 -0800856 mDataAdapter.removeData(dataID);
Doris Liu742cd5b2013-09-12 16:17:43 -0700857 if (mDataAdapter.getTotalNumber() > 1) {
858 showUndoDeletionBar();
859 } else {
860 // If camera preview is the only view left in filmstrip,
861 // no need to show undo bar.
Doris Liuf2c14332013-09-26 11:24:37 -0700862 mPendingDeletion = true;
Doris Liu742cd5b2013-09-12 16:17:43 -0700863 performDeletion();
864 }
Michael Kolb8872c232013-01-29 10:33:22 -0800865 }
866
ztenghui0353ca22013-08-13 13:53:16 -0700867 @Override
868 public boolean onOptionsItemSelected(MenuItem item) {
869 // Handle presses on the action bar items
870 switch (item.getItemId()) {
Alan Newberger3f969c12013-08-23 10:10:30 -0700871 case android.R.id.home:
Angus Kong248f42b2013-12-06 15:49:17 -0800872 onBackPressed();
873 return true;
ztenghui0353ca22013-08-13 13:53:16 -0700874 default:
875 return super.onOptionsItemSelected(item);
876 }
877 }
878
ztenghuifd43e3b2013-09-03 11:30:11 -0700879 private boolean isCaptureIntent() {
880 if (MediaStore.ACTION_VIDEO_CAPTURE.equals(getIntent().getAction())
881 || MediaStore.ACTION_IMAGE_CAPTURE.equals(getIntent().getAction())
882 || MediaStore.ACTION_IMAGE_CAPTURE_SECURE.equals(getIntent().getAction())) {
883 return true;
884 } else {
885 return false;
886 }
887 }
888
ztenghui0353ca22013-08-13 13:53:16 -0700889 @Override
Doris Liu6432cd62013-06-13 17:20:31 -0700890 public void onCreate(Bundle state) {
891 super.onCreate(state);
Sascha Haeberling048bf4d2013-10-06 17:49:51 -0700892 GcamHelper.init(getContentResolver());
893
ztenghui50df4702013-08-13 15:53:57 -0700894 getWindow().requestFeature(Window.FEATURE_ACTION_BAR);
Doris Liu1c94b7d2013-11-09 19:13:44 -0800895 setContentView(R.layout.activity_main);
ztenghuifa9e2cc2013-08-09 17:37:15 -0700896 mActionBar = getActionBar();
Doris Liuaa874422013-09-18 19:43:12 -0700897 mActionBar.addOnMenuVisibilityListener(this);
Angus Kong20fad242013-11-11 18:23:46 -0800898 mMainHandler = new MainHandler(getMainLooper());
899 mCameraController =
900 new CameraController(this, this, mMainHandler,
901 CameraManagerFactory.getAndroidCameraManager());
Kevin Gabayanffbc43c2013-12-09 11:41:50 -0800902 mPreferences = new ComboPreferences(getAndroidContext());
903 mContentResolver = this.getContentResolver();
Angus Kong40d95e92013-11-27 15:13:34 -0800904
Erin Dahlgren7f0151d2014-01-02 16:08:12 -0800905 mSettingsManager = new SettingsManager(this, mCameraController.getNumberOfCameras());
906
Angus Kong40d95e92013-11-27 15:13:34 -0800907 // Remove this after we get rid of ComboPreferences.
908 int cameraId = Integer.parseInt(mSettingsManager.get(SettingsManager.SETTING_CAMERA_ID));
Kevin Gabayanffbc43c2013-12-09 11:41:50 -0800909 mPreferences.setLocalId(this, cameraId);
910 CameraSettings.upgradeGlobalPreferences(mPreferences,
911 mCameraController.getNumberOfCameras());
Angus Kong20fad242013-11-11 18:23:46 -0800912 // TODO: Try to move all the resources allocation to happen as soon as
913 // possible so we can call module.init() at the earliest time.
914 mModuleManager = new ModuleManagerImpl();
Angus Kong612321f2013-11-18 16:17:43 -0800915 ModulesInfo.setupModules(this, mModuleManager);
ztenghuifa9e2cc2013-08-09 17:37:15 -0700916
Doris Liu70576b62013-11-14 20:30:33 -0800917 mModeListView = (ModeListView) findViewById(R.id.mode_list_layout);
Doris Liua20074f2013-12-09 15:19:06 -0800918 mModeListView.init(mModuleManager.getSupportedModeIndexList());
Michael Kolb08650182013-02-25 19:43:56 -0800919 if (ApiHelper.HAS_ROTATION_ANIMATION) {
Doris Liu6432cd62013-06-13 17:20:31 -0700920 setRotationAnimation();
Michael Kolb08650182013-02-25 19:43:56 -0800921 }
Doris Liuaa874422013-09-18 19:43:12 -0700922
Doris Liu6432cd62013-06-13 17:20:31 -0700923 // Check if this is in the secure camera mode.
924 Intent intent = getIntent();
925 String action = intent.getAction();
Doris Liub84b9732013-06-18 17:14:26 -0700926 if (INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE.equals(action)
927 || ACTION_IMAGE_CAPTURE_SECURE.equals(action)) {
Doris Liu6432cd62013-06-13 17:20:31 -0700928 mSecureCamera = true;
929 } else {
930 mSecureCamera = intent.getBooleanExtra(SECURE_CAMERA_EXTRA, false);
931 }
Doris Liub84b9732013-06-18 17:14:26 -0700932
933 if (mSecureCamera) {
934 // Change the window flags so that secure camera can show when locked
935 Window win = getWindow();
936 WindowManager.LayoutParams params = win.getAttributes();
937 params.flags |= WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
938 win.setAttributes(params);
939
940 // Filter for screen off so that we can finish secure camera activity
941 // when screen is off.
Doris Liu6432cd62013-06-13 17:20:31 -0700942 IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_OFF);
943 registerReceiver(mScreenOffReceiver, filter);
Doris Liub84b9732013-06-18 17:14:26 -0700944 }
Angus Kongb2510252013-12-10 22:58:15 -0800945 mCameraAppUI = new CameraAppUI(this,
946 (MainActivityLayout) findViewById(R.id.activity_root_view),
947 isSecureCamera(), isCaptureIntent());
948
949 mCameraAppUI.setFilmstripBottomControlsListener(mMyFilmstripBottomControlListener);
950
Angus Kong653c43b2013-08-21 18:28:43 -0700951 mAboveFilmstripControlLayout =
Angus Kongb95699e2013-12-07 13:52:51 -0800952 (FrameLayout) findViewById(R.id.camera_filmstrip_content_layout);
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800953
954 // Add the session listener so we can track the session progress updates.
955 getServices().getCaptureSessionManager().addSessionListener(mSessionListener);
956 mSessionProgressPanel = findViewById(R.id.pano_session_progress_panel);
957 mBottomProgressBar = (ProgressBar) findViewById(R.id.pano_session_progress_bar);
958 mBottomProgressText = (TextView) findViewById(R.id.pano_session_progress_text);
Angus Kong62848152013-11-08 17:25:29 -0800959 mFilmstripController = ((FilmstripView) findViewById(R.id.filmstrip_view)).getController();
Angus Kongfaaee012013-12-07 00:38:46 -0800960 mFilmstripController.setImageGap(
Doris Liu6432cd62013-06-13 17:20:31 -0700961 getResources().getDimensionPixelSize(R.dimen.camera_film_strip_gap));
Sascha Haeberlingf1f51862013-07-31 11:28:21 -0700962 mPanoramaViewHelper = new PanoramaViewHelper(this);
963 mPanoramaViewHelper.onCreate();
Doris Liu6432cd62013-06-13 17:20:31 -0700964 // Set up the camera preview first so the preview shows up ASAP.
Sascha Haeberling44c1afb2013-12-20 11:59:35 -0800965 mDataAdapter = new CameraDataAdapter(getApplicationContext(),
Angus Kong166e36f2013-12-03 08:54:42 -0800966 new ColorDrawable(getResources().getColor(R.color.photo_placeholder)));
Angus Konge2f4c032013-12-19 10:24:33 -0800967 mDataAdapter.setLocalDataListener(mLocalDataListener);
Angus Kongfaaee012013-12-07 00:38:46 -0800968
Spike Sprague0f3c4b42013-12-10 19:50:17 -0800969 mCameraAppUI.getFilmstripContentPanel().setFilmstripListener(mFilmstripListener);
Sascha Haeberling2654dd92013-08-28 15:28:57 -0700970
Kevin Gabayanffbc43c2013-12-09 11:41:50 -0800971 mLocationManager = new LocationManager(this);
Erin Dahlgren21c21a62013-11-19 16:37:38 -0800972
Erin Dahlgren357b7672013-11-20 17:38:14 -0800973 mSettingsController = new SettingsController(this, mSettingsManager, mLocationManager);
974
975 int modeIndex = -1;
976 if (MediaStore.INTENT_ACTION_VIDEO_CAMERA.equals(getIntent().getAction())
977 || MediaStore.ACTION_VIDEO_CAPTURE.equals(getIntent().getAction())) {
978 modeIndex = ModeListView.MODE_VIDEO;
979 } else if (MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA.equals(getIntent().getAction())
980 || MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE.equals(getIntent()
981 .getAction())) {
982 modeIndex = ModeListView.MODE_PHOTO;
Erin Dahlgren635a4b82013-11-25 15:21:18 -0800983 if (mSettingsManager.getInt(SettingsManager.SETTING_STARTUP_MODULE_INDEX)
Erin Dahlgren357b7672013-11-20 17:38:14 -0800984 == ModeListView.MODE_GCAM && GcamHelper.hasGcamCapture()) {
985 modeIndex = ModeListView.MODE_GCAM;
986 }
987 } else if (MediaStore.ACTION_IMAGE_CAPTURE.equals(getIntent().getAction())
988 || MediaStore.ACTION_IMAGE_CAPTURE_SECURE.equals(getIntent().getAction())) {
989 modeIndex = ModeListView.MODE_PHOTO;
990 } else {
991 // If the activity has not been started using an explicit intent,
992 // read the module index from the last time the user changed modes
Erin Dahlgren635a4b82013-11-25 15:21:18 -0800993 modeIndex = mSettingsManager.getInt(SettingsManager.SETTING_STARTUP_MODULE_INDEX);
Erin Dahlgren357b7672013-11-20 17:38:14 -0800994 if ((modeIndex == ModeListView.MODE_GCAM &&
995 !GcamHelper.hasGcamCapture()) || modeIndex < 0) {
996 modeIndex = ModeListView.MODE_PHOTO;
997 }
998 }
999
1000 mOrientationManager = new OrientationManagerImpl(this);
1001 mOrientationManager.addOnOrientationChangeListener(mMainHandler, this);
Erin Dahlgrenc120b0f2013-11-19 10:53:49 -08001002
1003 setModuleFromModeIndex(modeIndex);
Doris Liuf55f3c42013-11-20 00:24:46 -08001004
1005 // TODO: Remove this when refactor is done.
Erin Dahlgren5f500be2013-12-10 14:53:35 -08001006 if (modeIndex == ModulesInfo.MODULE_PHOTO
1007 || modeIndex == ModulesInfo.MODULE_VIDEO
Erin Dahlgren79fcbe42013-12-13 15:52:30 -08001008 || modeIndex == ModulesInfo.MODULE_GCAM
Erin Dahlgren4efa8b52013-12-17 18:31:35 -08001009 || modeIndex == ModulesInfo.MODULE_CRAFT
1010 || modeIndex == ModulesInfo.MODULE_REFOCUS) {
Doris Liuf55f3c42013-11-20 00:24:46 -08001011 mCameraAppUI.prepareModuleUI();
1012 }
Angus Kong13e87c42013-11-25 10:02:47 -08001013 mCurrentModule.init(this, isSecureCamera(), isCaptureIntent());
Sascha Haeberling37f36112013-08-06 14:31:52 -07001014
1015 if (!mSecureCamera) {
Angus Kong62848152013-11-08 17:25:29 -08001016 mFilmstripController.setDataAdapter(mDataAdapter);
Angus Konga7194602013-09-06 17:20:15 -07001017 if (!isCaptureIntent()) {
Sascha Haeberling44c1afb2013-12-20 11:59:35 -08001018 mDataAdapter.requestLoad();
Angus Konga7194602013-09-06 17:20:15 -07001019 }
Sascha Haeberling37f36112013-08-06 14:31:52 -07001020 } else {
Sascha Haeberlinga5a08d72013-09-11 20:30:52 -07001021 // Put a lock placeholder as the last image by setting its date to
1022 // 0.
Sascha Haeberling37f36112013-08-06 14:31:52 -07001023 ImageView v = (ImageView) getLayoutInflater().inflate(
1024 R.layout.secure_album_placeholder, null);
Angus Kong690dc472013-09-21 14:48:51 -07001025 v.setOnClickListener(new View.OnClickListener() {
1026 @Override
1027 public void onClick(View view) {
Angus Kongd3de1712013-12-12 22:01:12 -08001028 startGallery();
Angus Kong690dc472013-09-21 14:48:51 -07001029 finish();
1030 }
1031 });
Sascha Haeberling37f36112013-08-06 14:31:52 -07001032 mDataAdapter = new FixedLastDataAdapter(
Sascha Haeberling44c1afb2013-12-20 11:59:35 -08001033 getApplicationContext(),
Angus Kong166e36f2013-12-03 08:54:42 -08001034 mDataAdapter,
Angus Kongbd260692013-08-07 14:52:56 -07001035 new SimpleViewData(
Sascha Haeberling37f36112013-08-06 14:31:52 -07001036 v,
1037 v.getDrawable().getIntrinsicWidth(),
1038 v.getDrawable().getIntrinsicHeight(),
1039 0, 0));
1040 // Flush out all the original data.
1041 mDataAdapter.flush();
Angus Kong62848152013-11-08 17:25:29 -08001042 mFilmstripController.setDataAdapter(mDataAdapter);
Sascha Haeberling37f36112013-08-06 14:31:52 -07001043 }
Mangesh Ghiwarea5682ab2013-09-19 09:24:23 -07001044
1045 setupNfcBeamPush();
ztenghui064d6002013-09-05 15:47:58 -07001046
Doris Liu2b86d872013-09-26 15:23:41 -07001047 mLocalImagesObserver = new LocalMediaObserver();
1048 mLocalVideosObserver = new LocalMediaObserver();
ztenghui064d6002013-09-05 15:47:58 -07001049
1050 getContentResolver().registerContentObserver(
1051 MediaStore.Images.Media.EXTERNAL_CONTENT_URI, true,
1052 mLocalImagesObserver);
1053 getContentResolver().registerContentObserver(
1054 MediaStore.Video.Media.EXTERNAL_CONTENT_URI, true,
1055 mLocalVideosObserver);
Christian Wyglendowski6fe8c822013-11-26 14:16:04 -08001056 if (FeedbackHelper.feedbackAvailable()) {
1057 mFeedbackHelper = new FeedbackHelper(this);
1058 }
Michael Kolb8872c232013-01-29 10:33:22 -08001059 }
1060
Doris Liu6432cd62013-06-13 17:20:31 -07001061 private void setRotationAnimation() {
Michael Kolb08650182013-02-25 19:43:56 -08001062 int rotationAnimation = WindowManager.LayoutParams.ROTATION_ANIMATION_ROTATE;
Doris Liu6432cd62013-06-13 17:20:31 -07001063 rotationAnimation = WindowManager.LayoutParams.ROTATION_ANIMATION_CROSSFADE;
Michael Kolb08650182013-02-25 19:43:56 -08001064 Window win = getWindow();
1065 WindowManager.LayoutParams winParams = win.getAttributes();
1066 winParams.rotationAnimation = rotationAnimation;
1067 win.setAttributes(winParams);
1068 }
1069
Michael Kolb8872c232013-01-29 10:33:22 -08001070 @Override
Michael Kolb8872c232013-01-29 10:33:22 -08001071 public void onUserInteraction() {
1072 super.onUserInteraction();
Angus Kong13e87c42013-11-25 10:02:47 -08001073 if (!isFinishing()) {
1074 keepScreenOnForAWhile();
1075 }
Michael Kolb8872c232013-01-29 10:33:22 -08001076 }
1077
1078 @Override
Doris Liu742cd5b2013-09-12 16:17:43 -07001079 public boolean dispatchTouchEvent(MotionEvent ev) {
1080 boolean result = super.dispatchTouchEvent(ev);
1081 if (ev.getActionMasked() == MotionEvent.ACTION_DOWN) {
1082 // Real deletion is postponed until the next user interaction after
1083 // the gesture that triggers deletion. Until real deletion is performed,
1084 // users can click the undo button to bring back the image that they
1085 // chose to delete.
1086 if (mPendingDeletion && !mIsUndoingDeletion) {
Angus Kong20fad242013-11-11 18:23:46 -08001087 performDeletion();
Doris Liu742cd5b2013-09-12 16:17:43 -07001088 }
1089 }
1090 return result;
1091 }
1092
1093 @Override
Doris Liu6432cd62013-06-13 17:20:31 -07001094 public void onPause() {
Erin Dahlgrenc120b0f2013-11-19 10:53:49 -08001095 mPaused = true;
1096
Doris Liuf2c14332013-09-26 11:24:37 -07001097 // Delete photos that are pending deletion
1098 performDeletion();
Angus Kongc4e66562013-11-22 23:03:21 -08001099 mCurrentModule.pause();
Angus Kong9f1db522013-11-09 16:25:59 -08001100 mOrientationManager.pause();
Angus Kong20fad242013-11-11 18:23:46 -08001101 // Close the camera and wait for the operation done.
1102 mCameraController.closeCamera();
Doris Liu2b86d872013-09-26 15:23:41 -07001103
1104 mLocalImagesObserver.setActivityPaused(true);
1105 mLocalVideosObserver.setActivityPaused(true);
Angus Kong13e87c42013-11-25 10:02:47 -08001106 resetScreenOn();
Angus Kongc4e66562013-11-22 23:03:21 -08001107 super.onPause();
Doris Liu6432cd62013-06-13 17:20:31 -07001108 }
1109
1110 @Override
Sascha Haeberlingb7639c62013-09-09 14:42:43 -07001111 protected void onActivityResult(int requestCode, int resultCode, Intent data) {
ztenghui064d6002013-09-05 15:47:58 -07001112 if (requestCode == REQ_CODE_DONT_SWITCH_TO_PREVIEW) {
Sascha Haeberlingb7639c62013-09-09 14:42:43 -07001113 mResetToPreviewOnResume = false;
1114 } else {
1115 super.onActivityResult(requestCode, resultCode, data);
1116 }
1117 }
1118
1119 @Override
Doris Liu6432cd62013-06-13 17:20:31 -07001120 public void onResume() {
Erin Dahlgrenc120b0f2013-11-19 10:53:49 -08001121 mPaused = false;
1122
Angus Kong53ae0412013-12-01 23:21:49 -08001123 mLastLayoutOrientation = getResources().getConfiguration().orientation;
1124
Angus Kongce2b9492013-09-05 17:49:06 -07001125 // TODO: Handle this in OrientationManager.
Sascha Haeberlinga5a08d72013-09-11 20:30:52 -07001126 // Auto-rotate off
Doris Liu6432cd62013-06-13 17:20:31 -07001127 if (Settings.System.getInt(getContentResolver(),
Sascha Haeberlinga5a08d72013-09-11 20:30:52 -07001128 Settings.System.ACCELEROMETER_ROTATION, 0) == 0) {
Doris Liu6432cd62013-06-13 17:20:31 -07001129 setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
1130 mAutoRotateScreen = false;
1131 } else {
1132 setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR);
1133 mAutoRotateScreen = true;
1134 }
Seth Raphaelcbd82672013-11-05 10:12:36 -08001135
1136 UsageStatistics.onEvent(UsageStatistics.COMPONENT_CAMERA,
1137 UsageStatistics.ACTION_FOREGROUNDED, this.getClass().getSimpleName());
1138
Angus Kong9f1db522013-11-09 16:25:59 -08001139 mOrientationManager.resume();
Doris Liu6432cd62013-06-13 17:20:31 -07001140 super.onResume();
Angus Kongc4e66562013-11-22 23:03:21 -08001141 mCurrentModule.resume();
Angus Kong6798c342013-07-16 15:14:58 -07001142 setSwipingEnabled(true);
Sascha Haeberlingb7639c62013-09-09 14:42:43 -07001143
1144 if (mResetToPreviewOnResume) {
Doris Liu2b906b82013-12-10 16:34:08 -08001145 mCameraAppUI.resume();
Sascha Haeberlingb7639c62013-09-09 14:42:43 -07001146 }
Angus Konge4002f32013-12-13 22:24:11 -08001147 // The share button might be disabled to avoid double tapping.
1148 mCameraAppUI.getFilmstripBottomControls().setShareEnabled(true);
Sascha Haeberlingb7639c62013-09-09 14:42:43 -07001149 // Default is showing the preview, unless disabled by explicitly
1150 // starting an activity we want to return from to the filmstrip rather
1151 // than the preview.
1152 mResetToPreviewOnResume = true;
ztenghui064d6002013-09-05 15:47:58 -07001153
Doris Liu2b86d872013-09-26 15:23:41 -07001154 if (mLocalVideosObserver.isMediaDataChangedDuringPause()
1155 || mLocalImagesObserver.isMediaDataChangedDuringPause()) {
Angus Kong2d5c7472013-10-12 23:48:46 -07001156 if (!mSecureCamera) {
1157 // If it's secure camera, requestLoad() should not be called
1158 // as it will load all the data.
Angus Kongb2510252013-12-10 22:58:15 -08001159 if (!mFilmstripVisible) {
Sascha Haeberling44c1afb2013-12-20 11:59:35 -08001160 mDataAdapter.requestLoad();
Angus Kongb2510252013-12-10 22:58:15 -08001161 }
Angus Kong2d5c7472013-10-12 23:48:46 -07001162 }
ztenghui064d6002013-09-05 15:47:58 -07001163 }
Doris Liu2b86d872013-09-26 15:23:41 -07001164 mLocalImagesObserver.setActivityPaused(false);
1165 mLocalVideosObserver.setActivityPaused(false);
Doris Liu70576b62013-11-14 20:30:33 -08001166
Angus Kong13e87c42013-11-25 10:02:47 -08001167 keepScreenOnForAWhile();
Angus Kong6798c342013-07-16 15:14:58 -07001168 }
1169
1170 @Override
1171 public void onStart() {
1172 super.onStart();
Sascha Haeberlingf1f51862013-07-31 11:28:21 -07001173 mPanoramaViewHelper.onStart();
Kevin Gabayanffbc43c2013-12-09 11:41:50 -08001174 boolean recordLocation = RecordLocationPreference.get(
1175 mPreferences, mContentResolver);
1176 mLocationManager.recordLocation(recordLocation);
Sascha Haeberlingf1f51862013-07-31 11:28:21 -07001177 }
1178
1179 @Override
1180 protected void onStop() {
Sascha Haeberlingf1f51862013-07-31 11:28:21 -07001181 mPanoramaViewHelper.onStop();
Christian Wyglendowski6fe8c822013-11-26 14:16:04 -08001182 if (mFeedbackHelper != null) {
1183 mFeedbackHelper.stopFeedback();
1184 }
Angus Kong0e57fc12013-11-18 13:21:07 -08001185
Kevin Gabayanffbc43c2013-12-09 11:41:50 -08001186 mLocationManager.disconnect();
Angus Kong0e57fc12013-11-18 13:21:07 -08001187 CameraManagerFactory.recycle();
1188 super.onStop();
Doris Liu6432cd62013-06-13 17:20:31 -07001189 }
1190
1191 @Override
1192 public void onDestroy() {
Sascha Haeberlinga5a08d72013-09-11 20:30:52 -07001193 if (mSecureCamera) {
1194 unregisterReceiver(mScreenOffReceiver);
1195 }
Erin Dahlgren1648c362014-01-06 15:06:04 -08001196 mSettingsManager.removeAllListeners();
ztenghui064d6002013-09-05 15:47:58 -07001197 getContentResolver().unregisterContentObserver(mLocalImagesObserver);
1198 getContentResolver().unregisterContentObserver(mLocalVideosObserver);
Doris Liu6432cd62013-06-13 17:20:31 -07001199 super.onDestroy();
1200 }
1201
1202 @Override
1203 public void onConfigurationChanged(Configuration config) {
1204 super.onConfigurationChanged(config);
Angus Kong166e36f2013-12-03 08:54:42 -08001205 Log.v(TAG, "onConfigurationChanged");
Angus Kong2f0e4a32013-12-03 10:02:35 -08001206 if (config.orientation == Configuration.ORIENTATION_UNDEFINED) {
1207 return;
1208 }
1209
Angus Kong53ae0412013-12-01 23:21:49 -08001210 if (mLastLayoutOrientation != config.orientation) {
1211 mLastLayoutOrientation = config.orientation;
Angus Kong2f0e4a32013-12-03 10:02:35 -08001212 mCurrentModule.onLayoutOrientationChanged(
1213 mLastLayoutOrientation == Configuration.ORIENTATION_LANDSCAPE);
Angus Kong53ae0412013-12-01 23:21:49 -08001214 }
Doris Liu6432cd62013-06-13 17:20:31 -07001215 }
1216
1217 @Override
1218 public boolean onKeyDown(int keyCode, KeyEvent event) {
Angus Kong8dcccb12014-01-02 16:00:49 -08001219 if (!mFilmstripVisible) {
Doris Liudba16ae2013-10-03 15:31:40 -07001220 if (mCurrentModule.onKeyDown(keyCode, event)) {
Sascha Haeberlinga5a08d72013-09-11 20:30:52 -07001221 return true;
1222 }
Doris Liudba16ae2013-10-03 15:31:40 -07001223 // Prevent software keyboard or voice search from showing up.
1224 if (keyCode == KeyEvent.KEYCODE_SEARCH
1225 || keyCode == KeyEvent.KEYCODE_MENU) {
1226 if (event.isLongPress()) {
1227 return true;
1228 }
1229 }
Doris Liu6432cd62013-06-13 17:20:31 -07001230 }
Doris Liu6432cd62013-06-13 17:20:31 -07001231
1232 return super.onKeyDown(keyCode, event);
1233 }
1234
1235 @Override
1236 public boolean onKeyUp(int keyCode, KeyEvent event) {
Angus Kong8dcccb12014-01-02 16:00:49 -08001237 if (!mFilmstripVisible && mCurrentModule.onKeyUp(keyCode, event)) {
Sascha Haeberlinga5a08d72013-09-11 20:30:52 -07001238 return true;
1239 }
Doris Liu6432cd62013-06-13 17:20:31 -07001240 return super.onKeyUp(keyCode, event);
1241 }
1242
Alan Newberger5f6b50d2013-08-30 15:19:48 -07001243 @Override
1244 public void onBackPressed() {
Angus Kong166e36f2013-12-03 08:54:42 -08001245 if (!mCameraAppUI.onBackPressed()) {
1246 if (!mCurrentModule.onBackPressed()) {
1247 super.onBackPressed();
1248 }
Alan Newberger5f6b50d2013-08-30 15:19:48 -07001249 }
1250 }
1251
Doris Liu6432cd62013-06-13 17:20:31 -07001252 public boolean isAutoRotateScreen() {
1253 return mAutoRotateScreen;
1254 }
1255
1256 protected void updateStorageSpace() {
Angus Kong2dcc0a92013-09-25 13:00:08 -07001257 mStorageSpaceBytes = Storage.getAvailableSpace();
Doris Liu6432cd62013-06-13 17:20:31 -07001258 }
1259
Angus Kong2dcc0a92013-09-25 13:00:08 -07001260 protected long getStorageSpaceBytes() {
1261 return mStorageSpaceBytes;
Doris Liu6432cd62013-06-13 17:20:31 -07001262 }
1263
1264 protected void updateStorageSpaceAndHint() {
1265 updateStorageSpace();
Angus Kong2dcc0a92013-09-25 13:00:08 -07001266 updateStorageHint(mStorageSpaceBytes);
Doris Liu6432cd62013-06-13 17:20:31 -07001267 }
1268
1269 protected void updateStorageHint(long storageSpace) {
1270 String message = null;
1271 if (storageSpace == Storage.UNAVAILABLE) {
1272 message = getString(R.string.no_storage);
1273 } else if (storageSpace == Storage.PREPARING) {
1274 message = getString(R.string.preparing_sd);
1275 } else if (storageSpace == Storage.UNKNOWN_SIZE) {
1276 message = getString(R.string.access_sd_fail);
Angus Kong2dcc0a92013-09-25 13:00:08 -07001277 } else if (storageSpace <= Storage.LOW_STORAGE_THRESHOLD_BYTES) {
Doris Liu6432cd62013-06-13 17:20:31 -07001278 message = getString(R.string.spaceIsLow_content);
1279 }
1280
1281 if (message != null) {
1282 if (mStorageHint == null) {
1283 mStorageHint = OnScreenHint.makeText(this, message);
1284 } else {
1285 mStorageHint.setText(message);
1286 }
1287 mStorageHint.show();
1288 } else if (mStorageHint != null) {
1289 mStorageHint.cancel();
1290 mStorageHint = null;
1291 }
1292 }
1293
1294 protected void setResultEx(int resultCode) {
1295 mResultCodeForTesting = resultCode;
1296 setResult(resultCode);
1297 }
1298
1299 protected void setResultEx(int resultCode, Intent data) {
1300 mResultCodeForTesting = resultCode;
1301 mResultDataForTesting = data;
1302 setResult(resultCode, data);
1303 }
1304
1305 public int getResultCode() {
1306 return mResultCodeForTesting;
1307 }
1308
1309 public Intent getResultData() {
1310 return mResultDataForTesting;
1311 }
1312
1313 public boolean isSecureCamera() {
1314 return mSecureCamera;
Michael Kolb8872c232013-01-29 10:33:22 -08001315 }
1316
1317 @Override
Erin Dahlgrenc120b0f2013-11-19 10:53:49 -08001318 public boolean isPaused() {
1319 return mPaused;
1320 }
1321
1322 @Override
1323 public void onModeSelected(int modeIndex) {
1324 if (mCurrentModeIndex == modeIndex) {
Sascha Haeberlinga5a08d72013-09-11 20:30:52 -07001325 return;
1326 }
Doris Liu6432cd62013-06-13 17:20:31 -07001327
Doris Liuf55f3c42013-11-20 00:24:46 -08001328 if (modeIndex == ModeListView.MODE_SETTING) {
1329 onSettingsSelected();
1330 return;
1331 }
1332
Erin Dahlgrenc120b0f2013-11-19 10:53:49 -08001333 CameraHolder.instance().keep();
Doris Liu6432cd62013-06-13 17:20:31 -07001334 closeModule(mCurrentModule);
Doris Liuf55f3c42013-11-20 00:24:46 -08001335 int oldModuleIndex = mCurrentModeIndex;
Erin Dahlgrena340f072014-01-06 17:31:23 -08001336
1337 // Refocus and Gcam are modes that cannot be selected
1338 // from the mode list view, because they are not list items.
1339 // Check whether we should interpret MODULE_CRAFT as either.
1340 if (modeIndex == ModulesInfo.MODULE_CRAFT) {
1341 boolean refocusOn = mSettingsManager.isRefocusOn();
1342 boolean hdrPlusOn = mSettingsManager.isHdrPlusOn();
1343 if (refocusOn && hdrPlusOn) {
1344 throw new IllegalStateException("Refocus and hdr plus cannot be on together.");
1345 }
1346 if (refocusOn) {
1347 modeIndex = ModulesInfo.MODULE_REFOCUS;
1348 } else if (hdrPlusOn) {
1349 modeIndex = ModulesInfo.MODULE_GCAM;
1350 } else {
1351 // Do nothing, keep MODULE_CRAFT.
1352 }
1353 }
1354
Erin Dahlgrenc120b0f2013-11-19 10:53:49 -08001355 setModuleFromModeIndex(modeIndex);
Doris Liuf55f3c42013-11-20 00:24:46 -08001356
Erin Dahlgren5f500be2013-12-10 14:53:35 -08001357 // TODO: The following check is temporary for modules attached to the
1358 // generic_module layout. When the refactor is done, similar logic will
1359 // be applied to all modules.
Doris Liuf55f3c42013-11-20 00:24:46 -08001360 if (mCurrentModeIndex == ModulesInfo.MODULE_PHOTO
Erin Dahlgren5f500be2013-12-10 14:53:35 -08001361 || mCurrentModeIndex == ModulesInfo.MODULE_VIDEO
Erin Dahlgren79fcbe42013-12-13 15:52:30 -08001362 || mCurrentModeIndex == ModulesInfo.MODULE_GCAM
Erin Dahlgren4efa8b52013-12-17 18:31:35 -08001363 || mCurrentModeIndex == ModulesInfo.MODULE_CRAFT
1364 || mCurrentModeIndex == ModulesInfo.MODULE_REFOCUS) {
Doris Liuf55f3c42013-11-20 00:24:46 -08001365 if (oldModuleIndex != ModulesInfo.MODULE_PHOTO
Erin Dahlgren5f500be2013-12-10 14:53:35 -08001366 && oldModuleIndex != ModulesInfo.MODULE_VIDEO
Erin Dahlgren79fcbe42013-12-13 15:52:30 -08001367 && oldModuleIndex != ModulesInfo.MODULE_GCAM
Erin Dahlgren4efa8b52013-12-17 18:31:35 -08001368 && oldModuleIndex != ModulesInfo.MODULE_CRAFT
1369 && oldModuleIndex != ModulesInfo.MODULE_REFOCUS) {
Doris Liuf55f3c42013-11-20 00:24:46 -08001370 mCameraAppUI.prepareModuleUI();
1371 } else {
1372 mCameraAppUI.clearModuleUI();
1373 }
1374 } else {
1375 // This is the old way of removing all views in CameraRootView. Will
1376 // be deprecated soon. It is here to make sure modules that haven't
1377 // been refactored can still function.
1378 mCameraAppUI.clearCameraUI();
1379 }
1380
Sascha Haeberling2654dd92013-08-28 15:28:57 -07001381 openModule(mCurrentModule);
1382 mCurrentModule.onOrientationChanged(mLastRawOrientation);
Sascha Haeberling2654dd92013-08-28 15:28:57 -07001383 // Store the module index so we can use it the next time the Camera
1384 // starts up.
1385 SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
Erin Dahlgrenc120b0f2013-11-19 10:53:49 -08001386 prefs.edit().putInt(CameraSettings.KEY_STARTUP_MODULE_INDEX, modeIndex).apply();
1387 }
1388
Doris Liuf55f3c42013-11-20 00:24:46 -08001389 public void onSettingsSelected() {
Erin Dahlgrenc120b0f2013-11-19 10:53:49 -08001390 // Temporary until we finalize the touch flow.
1391 LayoutInflater inflater = getLayoutInflater();
1392 SettingsView settingsView = (SettingsView) inflater.inflate(R.layout.settings_list_layout,
1393 null, false);
Erin Dahlgren357b7672013-11-20 17:38:14 -08001394 settingsView.setSettingsListener(mSettingsController);
Christian Wyglendowski6fe8c822013-11-26 14:16:04 -08001395 if (mFeedbackHelper != null) {
1396 settingsView.setFeedbackHelper(mFeedbackHelper);
1397 }
Erin Dahlgren4bb80822013-11-27 10:42:10 -08001398 PopupWindow popup = new PopupWindow(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
Erin Dahlgrenc120b0f2013-11-19 10:53:49 -08001399 popup.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
1400 popup.setOutsideTouchable(true);
1401 popup.setFocusable(true);
1402 popup.setContentView(settingsView);
1403 popup.showAtLocation(mModeListView.getRootView(), Gravity.CENTER, 0, 0);
Sascha Haeberling2654dd92013-08-28 15:28:57 -07001404 }
1405
1406 /**
Sascha Haeberlinga5a08d72013-09-11 20:30:52 -07001407 * Sets the mCurrentModuleIndex, creates a new module instance for the given
1408 * index an sets it as mCurrentModule.
Sascha Haeberling2654dd92013-08-28 15:28:57 -07001409 */
Erin Dahlgrenc120b0f2013-11-19 10:53:49 -08001410 private void setModuleFromModeIndex(int modeIndex) {
1411 ModuleManagerImpl.ModuleAgent agent = mModuleManager.getModuleAgent(modeIndex);
Angus Kong20fad242013-11-11 18:23:46 -08001412 if (agent == null) {
1413 return;
Doris Liu6432cd62013-06-13 17:20:31 -07001414 }
Angus Kong20fad242013-11-11 18:23:46 -08001415 if (!agent.requestAppForCamera()) {
1416 mCameraController.closeCamera();
1417 }
Erin Dahlgrenc120b0f2013-11-19 10:53:49 -08001418 mCurrentModeIndex = agent.getModuleId();
Angus Kong13e87c42013-11-25 10:02:47 -08001419 mCurrentModule = (CameraModule) agent.createModule(this);
Michael Kolb8872c232013-01-29 10:33:22 -08001420 }
1421
Erin Dahlgrenc120b0f2013-11-19 10:53:49 -08001422 @Override
1423 public SettingsManager getSettingsManager() {
1424 return mSettingsManager;
1425 }
1426
Angus Kongc4e66562013-11-22 23:03:21 -08001427 @Override
1428 public CameraServices getServices() {
1429 return (CameraServices) getApplication();
1430 }
1431
Erin Dahlgren357b7672013-11-20 17:38:14 -08001432 @Override
1433 public SettingsController getSettingsController() {
1434 return mSettingsController;
1435 }
1436
Erin Dahlgren18e2ef62013-12-05 14:53:38 -08001437 public ButtonManager getButtonManager() {
Erin Dahlgren8a2933b2013-12-06 12:07:33 -08001438 if (mButtonManager == null) {
1439 mButtonManager = new ButtonManager(this);
1440 }
1441 return mButtonManager;
Erin Dahlgren18e2ef62013-12-05 14:53:38 -08001442 }
1443
Sascha Haeberling88ef7662013-08-15 17:19:22 -07001444 /**
Erin Dahlgren491c6282013-11-25 13:22:07 -08001445 * Creates an AlertDialog appropriate for choosing whether to enable location
1446 * on the first run of the app.
1447 */
1448 public AlertDialog getFirstTimeLocationAlert() {
1449 AlertDialog.Builder builder = new AlertDialog.Builder(this);
1450 builder = SettingsView.getFirstTimeLocationAlertBuilder(builder, mSettingsController);
1451 if (builder != null) {
1452 return builder.create();
1453 } else {
1454 return null;
1455 }
1456 }
1457
1458 /**
Sascha Haeberling88ef7662013-08-15 17:19:22 -07001459 * Launches an ACTION_EDIT intent for the given local data item.
1460 */
1461 public void launchEditor(LocalData data) {
1462 Intent intent = new Intent(Intent.ACTION_EDIT)
1463 .setDataAndType(data.getContentUri(), data.getMimeType())
1464 .setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
Erin Dahlgren05a04922013-11-07 11:35:10 -08001465 try {
Angus Kong0eaf0162013-12-16 15:53:30 -08001466 launchActivityByIntent(intent);
Erin Dahlgren05a04922013-11-07 11:35:10 -08001467 } catch (ActivityNotFoundException e) {
Angus Kong0eaf0162013-12-16 15:53:30 -08001468 launchActivityByIntent(Intent.createChooser(intent, null));
Erin Dahlgren05a04922013-11-07 11:35:10 -08001469 }
Sascha Haeberling88ef7662013-08-15 17:19:22 -07001470 }
1471
Sascha Haeberlinga5a08d72013-09-11 20:30:52 -07001472 /**
1473 * Launch the tiny planet editor.
1474 *
Angus Kong20fad242013-11-11 18:23:46 -08001475 * @param data The data must be a 360 degree stereographically mapped
1476 * panoramic image. It will not be modified, instead a new item
1477 * with the result will be added to the filmstrip.
Sascha Haeberlinga5a08d72013-09-11 20:30:52 -07001478 */
1479 public void launchTinyPlanetEditor(LocalData data) {
1480 TinyPlanetFragment fragment = new TinyPlanetFragment();
1481 Bundle bundle = new Bundle();
1482 bundle.putString(TinyPlanetFragment.ARGUMENT_URI, data.getContentUri().toString());
1483 bundle.putString(TinyPlanetFragment.ARGUMENT_TITLE, data.getTitle());
1484 fragment.setArguments(bundle);
1485 fragment.show(getFragmentManager(), "tiny_planet");
1486 }
1487
Doris Liu6432cd62013-06-13 17:20:31 -07001488 private void openModule(CameraModule module) {
Erin Dahlgren4efa8b52013-12-17 18:31:35 -08001489 // Currently not all modules use the generic_module UI.
1490 // TODO: once all modules have a bottom bar, move this
1491 // logic into the app.
1492 if (module.isUsingBottomBar()) {
1493 int color = mModeListView.getModeThemeColor(mCurrentModeIndex);
1494 mCameraAppUI.setBottomBarColor(color);
1495 }
1496
Angus Kong13e87c42013-11-25 10:02:47 -08001497 module.init(this, isSecureCamera(), isCaptureIntent());
Angus Kongc4e66562013-11-22 23:03:21 -08001498 module.resume();
Angus Kongfaaee012013-12-07 00:38:46 -08001499 module.onPreviewVisibilityChanged(!mFilmstripVisible);
Doris Liu6432cd62013-06-13 17:20:31 -07001500 }
1501
1502 private void closeModule(CameraModule module) {
Angus Kongc4e66562013-11-22 23:03:21 -08001503 module.pause();
Angus Kong653c43b2013-08-21 18:28:43 -07001504 }
1505
Doris Liu742cd5b2013-09-12 16:17:43 -07001506 private void performDeletion() {
1507 if (!mPendingDeletion) {
1508 return;
1509 }
1510 hideUndoDeletionBar(false);
Sascha Haeberling44c1afb2013-12-20 11:59:35 -08001511 mDataAdapter.executeDeletion();
Doris Liu742cd5b2013-09-12 16:17:43 -07001512 }
1513
1514 public void showUndoDeletionBar() {
1515 if (mPendingDeletion) {
1516 performDeletion();
1517 }
1518 Log.v(TAG, "showing undo bar");
1519 mPendingDeletion = true;
Angus Kong653c43b2013-08-21 18:28:43 -07001520 if (mUndoDeletionBar == null) {
Angus Kong20fad242013-11-11 18:23:46 -08001521 ViewGroup v = (ViewGroup) getLayoutInflater().inflate(R.layout.undo_bar,
1522 mAboveFilmstripControlLayout, true);
Angus Kong653c43b2013-08-21 18:28:43 -07001523 mUndoDeletionBar = (ViewGroup) v.findViewById(R.id.camera_undo_deletion_bar);
1524 View button = mUndoDeletionBar.findViewById(R.id.camera_undo_deletion_button);
1525 button.setOnClickListener(new View.OnClickListener() {
1526 @Override
1527 public void onClick(View view) {
1528 mDataAdapter.undoDataRemoval();
Doris Liu742cd5b2013-09-12 16:17:43 -07001529 hideUndoDeletionBar(true);
1530 }
1531 });
1532 // Setting undo bar clickable to avoid touch events going through
1533 // the bar to the buttons (eg. edit button, etc) underneath the bar.
1534 mUndoDeletionBar.setClickable(true);
1535 // When there is user interaction going on with the undo button, we
1536 // do not want to hide the undo bar.
1537 button.setOnTouchListener(new View.OnTouchListener() {
1538 @Override
1539 public boolean onTouch(View v, MotionEvent event) {
1540 if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
1541 mIsUndoingDeletion = true;
1542 } else if (event.getActionMasked() == MotionEvent.ACTION_UP) {
Angus Kong20fad242013-11-11 18:23:46 -08001543 mIsUndoingDeletion = false;
Doris Liu742cd5b2013-09-12 16:17:43 -07001544 }
1545 return false;
Angus Kong653c43b2013-08-21 18:28:43 -07001546 }
1547 });
1548 }
1549 mUndoDeletionBar.setAlpha(0f);
1550 mUndoDeletionBar.setVisibility(View.VISIBLE);
Doris Liu742cd5b2013-09-12 16:17:43 -07001551 mUndoDeletionBar.animate().setDuration(200).alpha(1f).setListener(null).start();
Angus Kong653c43b2013-08-21 18:28:43 -07001552 }
1553
Doris Liu742cd5b2013-09-12 16:17:43 -07001554 private void hideUndoDeletionBar(boolean withAnimation) {
Angus Kong653c43b2013-08-21 18:28:43 -07001555 Log.v(TAG, "Hiding undo deletion bar");
Doris Liu742cd5b2013-09-12 16:17:43 -07001556 mPendingDeletion = false;
Angus Kong653c43b2013-08-21 18:28:43 -07001557 if (mUndoDeletionBar != null) {
Doris Liu742cd5b2013-09-12 16:17:43 -07001558 if (withAnimation) {
Angus Kong20fad242013-11-11 18:23:46 -08001559 mUndoDeletionBar.animate().setDuration(200).alpha(0f)
Doris Liu742cd5b2013-09-12 16:17:43 -07001560 .setListener(new Animator.AnimatorListener() {
1561 @Override
1562 public void onAnimationStart(Animator animation) {
1563 // Do nothing.
1564 }
1565
1566 @Override
1567 public void onAnimationEnd(Animator animation) {
1568 mUndoDeletionBar.setVisibility(View.GONE);
1569 }
1570
1571 @Override
1572 public void onAnimationCancel(Animator animation) {
1573 // Do nothing.
1574 }
1575
1576 @Override
1577 public void onAnimationRepeat(Animator animation) {
1578 // Do nothing.
1579 }
Angus Kong20fad242013-11-11 18:23:46 -08001580 }).start();
Doris Liu742cd5b2013-09-12 16:17:43 -07001581 } else {
1582 mUndoDeletionBar.setVisibility(View.GONE);
1583 }
Angus Kong653c43b2013-08-21 18:28:43 -07001584 }
Michael Kolb8872c232013-01-29 10:33:22 -08001585 }
1586
1587 @Override
Angus Kong9f1db522013-11-09 16:25:59 -08001588 public void onOrientationChanged(int orientation) {
1589 // We keep the last known orientation. So if the user first orient
1590 // the camera then point the camera to floor or sky, we still have
1591 // the correct orientation.
1592 if (orientation == OrientationManager.ORIENTATION_UNKNOWN) {
1593 return;
1594 }
1595 mLastRawOrientation = orientation;
1596 if (mCurrentModule != null) {
1597 mCurrentModule.onOrientationChanged(orientation);
1598 }
1599 }
1600
Angus Konga7194602013-09-06 17:20:15 -07001601 /**
Sascha Haeberlinga5a08d72013-09-11 20:30:52 -07001602 * Enable/disable swipe-to-filmstrip. Will always disable swipe if in
1603 * capture intent.
Angus Konga7194602013-09-06 17:20:15 -07001604 *
1605 * @param enable {@code true} to enable swipe.
1606 */
Doris Liu6432cd62013-06-13 17:20:31 -07001607 public void setSwipingEnabled(boolean enable) {
Angus Kong166e36f2013-12-03 08:54:42 -08001608 // TODO: Bring back the functionality.
Angus Konga7194602013-09-06 17:20:15 -07001609 if (isCaptureIntent()) {
Angus Kong166e36f2013-12-03 08:54:42 -08001610 //lockPreview(true);
Angus Konga7194602013-09-06 17:20:15 -07001611 } else {
Angus Kong166e36f2013-12-03 08:54:42 -08001612 //lockPreview(!enable);
Angus Konga7194602013-09-06 17:20:15 -07001613 }
Michael Kolb8872c232013-01-29 10:33:22 -08001614 }
1615
1616 // Accessor methods for getting latency times used in performance testing
1617 public long getAutoFocusTime() {
1618 return (mCurrentModule instanceof PhotoModule) ?
1619 ((PhotoModule) mCurrentModule).mAutoFocusTime : -1;
1620 }
1621
1622 public long getShutterLag() {
1623 return (mCurrentModule instanceof PhotoModule) ?
1624 ((PhotoModule) mCurrentModule).mShutterLag : -1;
1625 }
1626
1627 public long getShutterToPictureDisplayedTime() {
1628 return (mCurrentModule instanceof PhotoModule) ?
1629 ((PhotoModule) mCurrentModule).mShutterToPictureDisplayedTime : -1;
1630 }
1631
1632 public long getPictureDisplayedToJpegCallbackTime() {
1633 return (mCurrentModule instanceof PhotoModule) ?
1634 ((PhotoModule) mCurrentModule).mPictureDisplayedToJpegCallbackTime : -1;
1635 }
1636
1637 public long getJpegCallbackFinishTime() {
1638 return (mCurrentModule instanceof PhotoModule) ?
1639 ((PhotoModule) mCurrentModule).mJpegCallbackFinishTime : -1;
1640 }
1641
1642 public long getCaptureStartTime() {
1643 return (mCurrentModule instanceof PhotoModule) ?
1644 ((PhotoModule) mCurrentModule).mCaptureStartTime : -1;
1645 }
1646
1647 public boolean isRecording() {
1648 return (mCurrentModule instanceof VideoModule) ?
1649 ((VideoModule) mCurrentModule).isRecording() : false;
1650 }
Angus Kong4f795b82013-09-16 14:25:35 -07001651
Angus Kong62848152013-11-08 17:25:29 -08001652 public CameraManager.CameraOpenCallback getCameraOpenErrorCallback() {
Angus Kong20fad242013-11-11 18:23:46 -08001653 return mCameraController;
Angus Kong4f795b82013-09-16 14:25:35 -07001654 }
Ruben Brunkd217ed02013-10-08 23:31:13 -07001655
1656 // For debugging purposes only.
1657 public CameraModule getCurrentModule() {
1658 return mCurrentModule;
1659 }
Angus Kong13e87c42013-11-25 10:02:47 -08001660
1661 private void keepScreenOnForAWhile() {
1662 if (mKeepScreenOn) {
1663 return;
1664 }
1665 mMainHandler.removeMessages(MSG_CLEAR_SCREEN_ON_FLAG);
1666 getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
1667 mMainHandler.sendEmptyMessageDelayed(MSG_CLEAR_SCREEN_ON_FLAG, SCREEN_DELAY_MS);
1668 }
1669
1670 private void resetScreenOn() {
1671 mKeepScreenOn = false;
1672 mMainHandler.removeMessages(MSG_CLEAR_SCREEN_ON_FLAG);
1673 getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
1674 }
Angus Kongb2510252013-12-10 22:58:15 -08001675
Angus Kongd3de1712013-12-12 22:01:12 -08001676 private void startGallery() {
1677 try {
1678 UsageStatistics.onEvent(UsageStatistics.COMPONENT_CAMERA,
1679 UsageStatistics.ACTION_GALLERY, null);
Angus Kong0eaf0162013-12-16 15:53:30 -08001680 launchActivityByIntent(IntentHelper.getGalleryIntent(CameraActivity.this));
Angus Kongd3de1712013-12-12 22:01:12 -08001681 } catch (ActivityNotFoundException e) {
1682 Log.w(TAG, "Failed to launch gallery activity, closing");
1683 }
1684 }
1685
Angus Kong662fbf42013-12-12 13:22:03 -08001686 private void setNfcBeamPushUriFromData(LocalData data) {
1687 final Uri uri = data.getContentUri();
1688 if (uri != Uri.EMPTY) {
1689 mNfcPushUris[0] = uri;
1690 } else {
1691 mNfcPushUris[0] = null;
1692 }
1693 }
1694
Angus Kongb2510252013-12-10 22:58:15 -08001695 /**
1696 * Updates the visibility of the filmstrip bottom controls.
1697 */
1698 private void updateUiByData(final int dataId) {
1699 if (isSecureCamera()) {
1700 // We cannot show buttons in secure camera since go to other
1701 // activities might create a security hole.
1702 return;
1703 }
1704
1705 final LocalData currentData = mDataAdapter.getLocalData(dataId);
1706 if (currentData == null) {
1707 Log.w(TAG, "Current data ID not found.");
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001708 hideSessionProgress();
Angus Kongb2510252013-12-10 22:58:15 -08001709 return;
1710 }
1711
Angus Kong662fbf42013-12-12 13:22:03 -08001712 setNfcBeamPushUriFromData(currentData);
1713
Angus Kongb2510252013-12-10 22:58:15 -08001714 /* Bottom controls. */
1715
Angus Konge2f4c032013-12-19 10:24:33 -08001716 updateBottomControlsByData(currentData);
1717 if (!mDataAdapter.isMetadataUpdated(dataId)) {
Sascha Haeberling44c1afb2013-12-20 11:59:35 -08001718 mDataAdapter.updateMetadata(dataId);
Angus Konge2f4c032013-12-19 10:24:33 -08001719 }
1720 }
1721
1722 /**
1723 * Updates the bottom controls based on the data.
1724 */
1725 private void updateBottomControlsByData(final LocalData currentData) {
1726
Angus Kongb2510252013-12-10 22:58:15 -08001727 final CameraAppUI.BottomControls filmstripBottomControls =
1728 mCameraAppUI.getFilmstripBottomControls();
Angus Kong740cbee2013-12-11 15:46:16 -08001729 filmstripBottomControls.setEditButtonVisibility(
1730 currentData.isDataActionSupported(LocalData.DATA_ACTION_EDIT));
Angus Konge0aff892013-12-11 20:51:01 -08001731 filmstripBottomControls.setShareButtonVisibility(
1732 currentData.isDataActionSupported(LocalData.DATA_ACTION_SHARE));
1733 filmstripBottomControls.setDeleteButtonVisibility(
1734 currentData.isDataActionSupported(LocalData.DATA_ACTION_DELETE));
Angus Kongb2510252013-12-10 22:58:15 -08001735
1736 /* Progress bar */
1737
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001738 Uri contentUri = currentData.getContentUri();
1739 CaptureSessionManager sessionManager = getServices()
1740 .getCaptureSessionManager();
1741 int sessionProgress = sessionManager.getSessionProgress(contentUri);
1742
1743 if (sessionProgress < 0) {
1744 hideSessionProgress();
Angus Kongb2510252013-12-10 22:58:15 -08001745 } else {
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001746 CharSequence progressMessage = sessionManager
1747 .getSessionProgressMessage(contentUri);
1748 showSessionProgress(progressMessage);
1749 updateSessionProgress(sessionProgress);
Angus Kongb2510252013-12-10 22:58:15 -08001750 }
1751
1752 /* View button */
1753
1754 // We need to add this to a separate DB.
Angus Kong8a2350a2013-12-16 15:02:34 -08001755 final int viewButtonVisibility;
1756 if (PanoramaMetadataLoader.isPanorama(currentData)) {
1757 viewButtonVisibility = CameraAppUI.BottomControls.VIEW_PHOTO_SPHERE;
1758 } else if (RgbzMetadataLoader.hasRGBZData(currentData)) {
1759 viewButtonVisibility = CameraAppUI.BottomControls.VIEW_RGBZ;
1760 } else {
1761 viewButtonVisibility = CameraAppUI.BottomControls.VIEW_NONE;
1762 }
Angus Kongb2510252013-12-10 22:58:15 -08001763
Angus Kong8a2350a2013-12-16 15:02:34 -08001764 filmstripBottomControls.setTinyPlanetButtonVisibility(
1765 PanoramaMetadataLoader.isPanorama360(currentData));
1766 filmstripBottomControls.setViewButtonVisibility(viewButtonVisibility);
Angus Kongb2510252013-12-10 22:58:15 -08001767 }
Michael Kolb8872c232013-01-29 10:33:22 -08001768}