blob: 82a82c2429e7ea5658b896f0257bf800bbc47ddb [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;
Mangesh Ghiware30968d02013-10-02 14:38:12 -070023import android.content.ActivityNotFoundException;
Doris Liub84b9732013-06-18 17:14:26 -070024import android.content.BroadcastReceiver;
Angus Kong86d36312013-01-31 18:22:44 -080025import android.content.ComponentName;
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;
Angus Kong86d36312013-01-31 18:22:44 -080030import android.content.ServiceConnection;
Sascha Haeberling2654dd92013-08-28 15:28:57 -070031import android.content.SharedPreferences;
Doris Liu3cf565c2013-02-15 10:55:37 -080032import android.content.pm.ActivityInfo;
Michael Kolb8872c232013-01-29 10:33:22 -080033import android.content.res.Configuration;
Angus Kong9f1db522013-11-09 16:25:59 -080034import android.graphics.Bitmap;
35import android.graphics.SurfaceTexture;
Doris Liu6432cd62013-06-13 17:20:31 -070036import android.graphics.drawable.ColorDrawable;
37import android.net.Uri;
Mangesh Ghiwarea5682ab2013-09-19 09:24:23 -070038import android.nfc.NfcAdapter;
39import android.nfc.NfcAdapter.CreateBeamUrisCallback;
40import android.nfc.NfcEvent;
Sascha Haeberling6f64b502013-08-14 16:23:18 -070041import android.os.AsyncTask;
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;
Angus Kong86d36312013-01-31 18:22:44 -080045import android.os.IBinder;
Doris Liuaa874422013-09-18 19:43:12 -070046import android.os.Looper;
47import android.os.Message;
Sascha Haeberling2654dd92013-08-28 15:28:57 -070048import android.preference.PreferenceManager;
Doris Liu2a7f44c2013-08-12 15:18:53 -070049import android.provider.MediaStore;
Doris Liu3cf565c2013-02-15 10:55:37 -080050import android.provider.Settings;
Sascha Haeberling37f36112013-08-06 14:31:52 -070051import android.util.Log;
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.Menu;
55import android.view.MenuInflater;
56import android.view.MenuItem;
Doris Liu742cd5b2013-09-12 16:17:43 -070057import android.view.MotionEvent;
Michael Kolb8872c232013-01-29 10:33:22 -080058import android.view.View;
Doris Liu6432cd62013-06-13 17:20:31 -070059import android.view.ViewGroup;
Michael Kolb08650182013-02-25 19:43:56 -080060import android.view.Window;
61import android.view.WindowManager;
Angus Kong653c43b2013-08-21 18:28:43 -070062import android.widget.FrameLayout;
Doris Liu6432cd62013-06-13 17:20:31 -070063import android.widget.ImageView;
Sascha Haeberling37f36112013-08-06 14:31:52 -070064import android.widget.ProgressBar;
Mangesh Ghiwarecd2eeb02013-08-23 13:28:21 -070065import android.widget.ShareActionProvider;
Michael Kolb8872c232013-01-29 10:33:22 -080066
Angus Kong9f1db522013-11-09 16:25:59 -080067import com.android.camera.app.AppController;
Angus Konged15d1a2013-08-19 15:06:12 -070068import com.android.camera.app.AppManagerFactory;
Angus Kong20fad242013-11-11 18:23:46 -080069import com.android.camera.app.CameraController;
70import com.android.camera.app.CameraManager;
71import com.android.camera.app.CameraManagerFactory;
72import com.android.camera.app.CameraProvider;
Angus Kong62848152013-11-08 17:25:29 -080073import com.android.camera.app.ImageTaskManager;
Angus Kongfd4fc0e2013-11-07 15:38:09 -080074import com.android.camera.app.MediaSaver;
Angus Kong20fad242013-11-11 18:23:46 -080075import com.android.camera.app.ModuleManagerImpl;
Angus Kong9f1db522013-11-09 16:25:59 -080076import com.android.camera.app.OrientationManager;
77import com.android.camera.app.OrientationManagerImpl;
Angus Konged15d1a2013-08-19 15:06:12 -070078import com.android.camera.app.PanoramaStitchingManager;
Angus Kong20fad242013-11-11 18:23:46 -080079import com.android.camera.app.PlaceholderManager;
nicolasroard19ab7252013-09-18 16:54:05 -070080import com.android.camera.crop.CropActivity;
Doris Liu6432cd62013-06-13 17:20:31 -070081import com.android.camera.data.CameraDataAdapter;
Angus Kong8e5e4ee2013-07-30 11:36:00 -070082import com.android.camera.data.CameraPreviewData;
83import com.android.camera.data.FixedFirstDataAdapter;
84import com.android.camera.data.FixedLastDataAdapter;
Angus Kong32509872013-10-02 16:53:40 -070085import com.android.camera.data.InProgressDataWrapper;
Doris Liu6432cd62013-06-13 17:20:31 -070086import com.android.camera.data.LocalData;
Angus Kong8e5e4ee2013-07-30 11:36:00 -070087import com.android.camera.data.LocalDataAdapter;
ztenghui064d6002013-09-05 15:47:58 -070088import com.android.camera.data.LocalMediaObserver;
Sascha Haeberling6f64b502013-08-14 16:23:18 -070089import com.android.camera.data.MediaDetails;
Angus Kongbd260692013-08-07 14:52:56 -070090import com.android.camera.data.SimpleViewData;
Angus Kong62848152013-11-08 17:25:29 -080091import com.android.camera.filmstrip.FilmstripController;
92import com.android.camera.filmstrip.FilmstripImageData;
93import com.android.camera.filmstrip.FilmstripListener;
Angus Kong20fad242013-11-11 18:23:46 -080094import com.android.camera.module.ModuleController;
Sascha Haeberlinga5a08d72013-09-11 20:30:52 -070095import com.android.camera.tinyplanet.TinyPlanetFragment;
Sascha Haeberling6f64b502013-08-14 16:23:18 -070096import com.android.camera.ui.DetailsDialog;
Angus Kong62848152013-11-08 17:25:29 -080097import com.android.camera.ui.FilmstripView;
Doris Liu1c94b7d2013-11-09 19:13:44 -080098import com.android.camera.ui.ModeListView;
Sascha Haeberling88ef7662013-08-15 17:19:22 -070099import com.android.camera.util.ApiHelper;
Angus Kongb50b5cb2013-08-09 14:55:20 -0700100import com.android.camera.util.CameraUtil;
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700101import com.android.camera.util.GcamHelper;
Alan Newberger761306f2013-10-30 12:51:21 -0700102import com.android.camera.util.IntentHelper;
Sascha Haeberling37f36112013-08-06 14:31:52 -0700103import com.android.camera.util.PhotoSphereHelper;
Sascha Haeberling88ef7662013-08-15 17:19:22 -0700104import com.android.camera.util.PhotoSphereHelper.PanoramaViewHelper;
Sascha Haeberling03e01452013-10-07 13:21:33 -0700105import com.android.camera.util.RefocusHelper;
Seth Raphaelcbd82672013-11-05 10:12:36 -0800106import com.android.camera.util.UsageStatistics;
Sascha Haeberling8e963a52013-08-06 11:43:02 -0700107import com.android.camera2.R;
Michael Kolb8872c232013-01-29 10:33:22 -0800108
Seth Raphaelcbd82672013-11-05 10:12:36 -0800109import java.io.File;
110
Doris Liu6432cd62013-06-13 17:20:31 -0700111public class CameraActivity extends Activity
Angus Kong20fad242013-11-11 18:23:46 -0800112 implements AppController, ModeListView.ModeSwitchListener, CameraManager.CameraOpenCallback,
Angus Kong9f1db522013-11-09 16:25:59 -0800113 ActionBar.OnMenuVisibilityListener, ShareActionProvider.OnShareTargetSelectedListener,
114 OrientationManager.OnOrientationChangeListener {
Doris Liu6432cd62013-06-13 17:20:31 -0700115
116 private static final String TAG = "CAM_Activity";
117
Doris Liu6432cd62013-06-13 17:20:31 -0700118 private static final String INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE =
119 "android.media.action.STILL_IMAGE_CAMERA_SECURE";
120 public static final String ACTION_IMAGE_CAPTURE_SECURE =
121 "android.media.action.IMAGE_CAPTURE_SECURE";
ztenghui6b920322013-08-16 16:21:22 -0700122 public static final String ACTION_TRIM_VIDEO =
123 "com.android.camera.action.TRIM";
124 public static final String MEDIA_ITEM_PATH = "media-item-path";
Doris Liu6432cd62013-06-13 17:20:31 -0700125
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
Doris Liuaa874422013-09-18 19:43:12 -0700140 private static final int HIDE_ACTION_BAR = 1;
141 private static final long SHOW_ACTION_BAR_TIMEOUT_MS = 3000;
142
Angus Kong20fad242013-11-11 18:23:46 -0800143 /**
144 * Whether onResume should reset the view to the preview.
145 */
Sascha Haeberlingb7639c62013-09-09 14:42:43 -0700146 private boolean mResetToPreviewOnResume = true;
147
ztenghui0353ca22013-08-13 13:53:16 -0700148 // Supported operations at FilmStripView. Different data has different
149 // set of supported operations.
150 private static final int SUPPORT_DELETE = 1 << 0;
151 private static final int SUPPORT_ROTATE = 1 << 1;
152 private static final int SUPPORT_INFO = 1 << 2;
153 private static final int SUPPORT_CROP = 1 << 3;
154 private static final int SUPPORT_SETAS = 1 << 4;
155 private static final int SUPPORT_EDIT = 1 << 5;
156 private static final int SUPPORT_TRIM = 1 << 6;
Mangesh Ghiwarecd2eeb02013-08-23 13:28:21 -0700157 private static final int SUPPORT_SHARE = 1 << 7;
158 private static final int SUPPORT_SHARE_PANORAMA360 = 1 << 8;
159 private static final int SUPPORT_SHOW_ON_MAP = 1 << 9;
ztenghui0353ca22013-08-13 13:53:16 -0700160 private static final int SUPPORT_ALL = 0xffffffff;
161
Angus Kong20fad242013-11-11 18:23:46 -0800162 /**
163 * This data adapter is used by FilmStripView.
164 */
Angus Kong8e5e4ee2013-07-30 11:36:00 -0700165 private LocalDataAdapter mDataAdapter;
Angus Kong20fad242013-11-11 18:23:46 -0800166 /**
167 * This data adapter represents the real local camera data.
168 */
Angus Kong8e5e4ee2013-07-30 11:36:00 -0700169 private LocalDataAdapter mWrappedDataAdapter;
170
Angus Kong6798c342013-07-16 15:14:58 -0700171 private PanoramaStitchingManager mPanoramaManager;
Ruben Brunk7cfcafd2013-10-17 15:41:44 -0700172 private PlaceholderManager mPlaceholderManager;
Michael Kolb8872c232013-01-29 10:33:22 -0800173 private int mCurrentModuleIndex;
Doris Liu6432cd62013-06-13 17:20:31 -0700174 private CameraModule mCurrentModule;
Angus Kong20fad242013-11-11 18:23:46 -0800175 private ModuleController mCurrentModule2;
176 private ModuleManagerImpl mModuleManager;
Angus Kong653c43b2013-08-21 18:28:43 -0700177 private FrameLayout mAboveFilmstripControlLayout;
Angus Kong9f1db522013-11-09 16:25:59 -0800178 private FrameLayout mCameraModuleRootView;
Angus Kong62848152013-11-08 17:25:29 -0800179 private FilmstripController mFilmstripController;
Sascha Haeberling37f36112013-08-06 14:31:52 -0700180 private ProgressBar mBottomProgress;
181 private View mPanoStitchingPanel;
Doris Liu6432cd62013-06-13 17:20:31 -0700182 private int mResultCodeForTesting;
183 private Intent mResultDataForTesting;
184 private OnScreenHint mStorageHint;
Angus Kong2dcc0a92013-09-25 13:00:08 -0700185 private long mStorageSpaceBytes = Storage.LOW_STORAGE_THRESHOLD_BYTES;
Doris Liu3cf565c2013-02-15 10:55:37 -0800186 private boolean mAutoRotateScreen;
Doris Liu6432cd62013-06-13 17:20:31 -0700187 private boolean mSecureCamera;
Angus Kong6a8e8a12013-07-19 14:55:07 -0700188 // This is a hack to speed up the start of SecureCamera.
189 private static boolean sFirstStartAfterScreenOn = true;
Doris Liu6432cd62013-06-13 17:20:31 -0700190 private int mLastRawOrientation;
Angus Kong9f1db522013-11-09 16:25:59 -0800191 private OrientationManagerImpl mOrientationManager;
Doris Liu6432cd62013-06-13 17:20:31 -0700192 private Handler mMainHandler;
Sascha Haeberlingf1f51862013-07-31 11:28:21 -0700193 private PanoramaViewHelper mPanoramaViewHelper;
Angus Kong8e5e4ee2013-07-30 11:36:00 -0700194 private CameraPreviewData mCameraPreviewData;
ztenghuifa9e2cc2013-08-09 17:37:15 -0700195 private ActionBar mActionBar;
Doris Liuaa874422013-09-18 19:43:12 -0700196 private OnActionBarVisibilityListener mOnActionBarVisibilityListener = null;
ztenghui0353ca22013-08-13 13:53:16 -0700197 private Menu mActionBarMenu;
Angus Kong653c43b2013-08-21 18:28:43 -0700198 private ViewGroup mUndoDeletionBar;
Doris Liu742cd5b2013-09-12 16:17:43 -0700199 private boolean mIsUndoingDeletion = false;
Doris Liu3cf565c2013-02-15 10:55:37 -0800200
Mangesh Ghiwarea5682ab2013-09-19 09:24:23 -0700201 private Uri[] mNfcPushUris = new Uri[1];
202
Mangesh Ghiwarecd2eeb02013-08-23 13:28:21 -0700203 private ShareActionProvider mStandardShareActionProvider;
204 private Intent mStandardShareIntent;
205 private ShareActionProvider mPanoramaShareActionProvider;
206 private Intent mPanoramaShareIntent;
ztenghui064d6002013-09-05 15:47:58 -0700207 private LocalMediaObserver mLocalImagesObserver;
208 private LocalMediaObserver mLocalVideosObserver;
Mangesh Ghiwarecd2eeb02013-08-23 13:28:21 -0700209
Sascha Haeberling5199c202013-09-05 17:10:19 -0700210 private final int DEFAULT_SYSTEM_UI_VISIBILITY = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
211 | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
Doris Liu742cd5b2013-09-12 16:17:43 -0700212 private boolean mPendingDeletion = false;
Sascha Haeberling5199c202013-09-05 17:10:19 -0700213
ztenghui05804752013-09-17 11:33:02 -0700214 private Intent mVideoShareIntent;
215 private Intent mImageShareIntent;
216
Angus Kong20fad242013-11-11 18:23:46 -0800217 private CameraController mCameraController;
218
Angus Kongfd4fc0e2013-11-07 15:38:09 -0800219 private MediaSaver mMediaSaver;
Doris Liu6432cd62013-06-13 17:20:31 -0700220 private ServiceConnection mConnection = new ServiceConnection() {
Sascha Haeberlinga5a08d72013-09-11 20:30:52 -0700221 @Override
222 public void onServiceConnected(ComponentName className, IBinder b) {
Angus Kongfd4fc0e2013-11-07 15:38:09 -0800223 mMediaSaver = ((MediaSaveService.LocalBinder) b).getService();
224 mCurrentModule.onMediaSaverAvailable(mMediaSaver);
Sascha Haeberlinga5a08d72013-09-11 20:30:52 -0700225 }
226
227 @Override
228 public void onServiceDisconnected(ComponentName className) {
Angus Kongfd4fc0e2013-11-07 15:38:09 -0800229 if (mMediaSaver != null) {
230 mMediaSaver.setQueueListener(null);
231 mMediaSaver = null;
Michael Kolb8872c232013-01-29 10:33:22 -0800232 }
Sascha Haeberlinga5a08d72013-09-11 20:30:52 -0700233 }
234 };
Doris Liu6432cd62013-06-13 17:20:31 -0700235
Angus Kong4f795b82013-09-16 14:25:35 -0700236
Doris Liub84b9732013-06-18 17:14:26 -0700237 // close activity when screen turns off
238 private BroadcastReceiver mScreenOffReceiver = new BroadcastReceiver() {
239 @Override
240 public void onReceive(Context context, Intent intent) {
241 finish();
242 }
243 };
244
Angus Kong6a8e8a12013-07-19 14:55:07 -0700245 private static BroadcastReceiver sScreenOffReceiver;
Sascha Haeberlinga5a08d72013-09-11 20:30:52 -0700246
Angus Kong20fad242013-11-11 18:23:46 -0800247 @Override
248 public void onCameraOpened(CameraManager.CameraProxy camera) {
249 if (!mModuleManager.getModuleAgent(mCurrentModuleIndex).requestAppForCamera()) {
250 // We shouldn't be here. Just close the camera and leave.
251 camera.release(false);
252 throw new IllegalStateException("Camera opened but the module shouldn't be " +
253 "requesting");
254 }
255 if (mCurrentModule2 != null) {
256 mCurrentModule2.onCameraAvailable(camera);
257 }
258 }
259
260 @Override
261 public void onCameraDisabled(int cameraId) {
262 UsageStatistics.onEvent(UsageStatistics.COMPONENT_CAMERA, UsageStatistics.ACTION_OPEN_FAIL,
263 "security");
264
265 CameraUtil.showErrorAndFinish(this, R.string.camera_disabled);
266 }
267
268 @Override
269 public void onDeviceOpenFailure(int cameraId) {
270 UsageStatistics.onEvent(UsageStatistics.COMPONENT_CAMERA,
271 UsageStatistics.ACTION_OPEN_FAIL, "open");
272
273 CameraUtil.showErrorAndFinish(this, R.string.cannot_connect_camera);
274 }
275
276 @Override
277 public void onReconnectionFailure(CameraManager mgr) {
278 UsageStatistics.onEvent(UsageStatistics.COMPONENT_CAMERA,
279 UsageStatistics.ACTION_OPEN_FAIL, "reconnect");
280
281 CameraUtil.showErrorAndFinish(this, R.string.cannot_connect_camera);
282 }
283
Angus Kong6a8e8a12013-07-19 14:55:07 -0700284 private static class ScreenOffReceiver extends BroadcastReceiver {
285 @Override
286 public void onReceive(Context context, Intent intent) {
287 sFirstStartAfterScreenOn = true;
288 }
289 }
290
Doris Liuaa874422013-09-18 19:43:12 -0700291 private class MainHandler extends Handler {
292 public MainHandler(Looper looper) {
293 super(looper);
294 }
295
296 @Override
297 public void handleMessage(Message msg) {
298 if (msg.what == HIDE_ACTION_BAR) {
299 removeMessages(HIDE_ACTION_BAR);
300 CameraActivity.this.setSystemBarsVisibility(false);
301 }
302 }
303 }
304
305 public interface OnActionBarVisibilityListener {
306 public void onActionBarVisibilityChanged(boolean isVisible);
307 }
308
309 public void setOnActionBarVisibilityListener(OnActionBarVisibilityListener listener) {
310 mOnActionBarVisibilityListener = listener;
311 }
312
Angus Kong6a8e8a12013-07-19 14:55:07 -0700313 public static boolean isFirstStartAfterScreenOn() {
314 return sFirstStartAfterScreenOn;
315 }
316
317 public static void resetFirstStartAfterScreenOn() {
318 sFirstStartAfterScreenOn = false;
319 }
320
Seth Raphaelcbd82672013-11-05 10:12:36 -0800321 private String fileNameFromDataID(int dataID) {
322 final LocalData localData = mDataAdapter.getLocalData(dataID);
323
324 File localFile = new File(localData.getPath());
325 return localFile.getName();
326 }
327
Angus Kong62848152013-11-08 17:25:29 -0800328 private FilmstripListener mFilmStripListener =
329 new FilmstripListener() {
Sascha Haeberling37f36112013-08-06 14:31:52 -0700330 @Override
331 public void onDataPromoted(int dataID) {
Seth Raphaelcbd82672013-11-05 10:12:36 -0800332 UsageStatistics.onEvent(UsageStatistics.COMPONENT_CAMERA,
333 UsageStatistics.ACTION_DELETE, "promoted", 0,
334 UsageStatistics.hashFileName(fileNameFromDataID(dataID)));
335
Sascha Haeberling37f36112013-08-06 14:31:52 -0700336 removeData(dataID);
337 }
Doris Liu6432cd62013-06-13 17:20:31 -0700338
Sascha Haeberling37f36112013-08-06 14:31:52 -0700339 @Override
340 public void onDataDemoted(int dataID) {
Seth Raphaelcbd82672013-11-05 10:12:36 -0800341 UsageStatistics.onEvent(UsageStatistics.COMPONENT_CAMERA,
342 UsageStatistics.ACTION_DELETE, "demoted", 0,
343 UsageStatistics.hashFileName(fileNameFromDataID(dataID)));
344
Sascha Haeberling37f36112013-08-06 14:31:52 -0700345 removeData(dataID);
346 }
Doris Liu6432cd62013-06-13 17:20:31 -0700347
Sascha Haeberling37f36112013-08-06 14:31:52 -0700348 @Override
349 public void onDataFullScreenChange(int dataID, boolean full) {
ztenghui8566dd72013-09-12 14:56:56 -0700350 boolean isCameraID = isCameraPreview(dataID);
ztenghui7b265a62013-09-09 14:58:44 -0700351 if (!isCameraID) {
Doris Liuaa874422013-09-18 19:43:12 -0700352 if (!full) {
353 // Always show action bar in filmstrip mode
354 CameraActivity.this.setSystemBarsVisibility(true, false);
355 } else if (mActionBar.isShowing()) {
356 // Hide action bar after time out in full screen mode
357 mMainHandler.sendEmptyMessageDelayed(HIDE_ACTION_BAR,
358 SHOW_ACTION_BAR_TIMEOUT_MS);
359 }
ztenghuifa9e2cc2013-08-09 17:37:15 -0700360 }
Sascha Haeberling37f36112013-08-06 14:31:52 -0700361 }
362
ztenghui8566dd72013-09-12 14:56:56 -0700363 /**
364 * Check if the local data corresponding to dataID is the camera
365 * preview.
366 *
367 * @param dataID the ID of the local data
368 * @return true if the local data is not null and it is the
369 * camera preview.
370 */
371 private boolean isCameraPreview(int dataID) {
372 LocalData localData = mDataAdapter.getLocalData(dataID);
373 if (localData == null) {
374 Log.w(TAG, "Current data ID not found.");
375 return false;
376 }
377 return localData.getLocalDataType() == LocalData.LOCAL_CAMERA_PREVIEW;
378 }
379
Sascha Haeberling37f36112013-08-06 14:31:52 -0700380 @Override
Angus Kongc02b13a2013-11-12 11:50:57 -0800381 public void onDataReloaded() {
Erin Dahlgren3044d8c2013-10-10 18:23:45 -0700382 setPreviewControlsVisibility(true);
ztenghui17f1e652013-11-06 14:20:31 -0800383 CameraActivity.this.setSystemBarsVisibility(false);
Erin Dahlgren3044d8c2013-10-10 18:23:45 -0700384 }
385
386 @Override
387 public void onCurrentDataCentered(int dataID) {
Angus Kong62848152013-11-08 17:25:29 -0800388 if (dataID != 0 && !mFilmstripController.isCameraPreview()) {
Erin Dahlgren3044d8c2013-10-10 18:23:45 -0700389 // For now, We ignore all items that are not the camera preview.
390 return;
391 }
392
Angus Kong20fad242013-11-11 18:23:46 -0800393 if (!arePreviewControlsVisible()) {
Erin Dahlgren3044d8c2013-10-10 18:23:45 -0700394 setPreviewControlsVisibility(true);
Erin Dahlgrenfd7f0a92013-10-21 10:08:54 -0700395 CameraActivity.this.setSystemBarsVisibility(false);
Erin Dahlgren3044d8c2013-10-10 18:23:45 -0700396 }
397 }
398
399 @Override
400 public void onCurrentDataOffCentered(int dataID) {
Angus Kong62848152013-11-08 17:25:29 -0800401 if (dataID != 0 && !mFilmstripController.isCameraPreview()) {
Erin Dahlgren3044d8c2013-10-10 18:23:45 -0700402 // For now, We ignore all items that are not the camera preview.
403 return;
404 }
405
406 if (arePreviewControlsVisible()) {
407 setPreviewControlsVisibility(false);
408 }
409 }
410
411 @Override
Angus Kong02cafdf2013-10-13 19:26:02 -0700412 public void onDataFocusChanged(final int dataID, final boolean focused) {
Doris Liuaa874422013-09-18 19:43:12 -0700413 // Delay hiding action bar if there is any user interaction
414 if (mMainHandler.hasMessages(HIDE_ACTION_BAR)) {
415 mMainHandler.removeMessages(HIDE_ACTION_BAR);
416 mMainHandler.sendEmptyMessageDelayed(HIDE_ACTION_BAR,
417 SHOW_ACTION_BAR_TIMEOUT_MS);
418 }
Angus Kong02cafdf2013-10-13 19:26:02 -0700419 // TODO: This callback is UI event callback, should always
420 // happen on UI thread. Find the reason for this
421 // runOnUiThread() and fix it.
Mangesh Ghiware33035c12013-08-23 13:28:21 -0700422 runOnUiThread(new Runnable() {
423 @Override
424 public void run() {
ztenghui7b265a62013-09-09 14:58:44 -0700425 LocalData currentData = mDataAdapter.getLocalData(dataID);
426 if (currentData == null) {
427 Log.w(TAG, "Current data ID not found.");
428 hidePanoStitchingProgress();
429 return;
430 }
431 boolean isCameraID = currentData.getLocalDataType() ==
432 LocalData.LOCAL_CAMERA_PREVIEW;
Angus Kong02cafdf2013-10-13 19:26:02 -0700433 if (!focused) {
ztenghui7b265a62013-09-09 14:58:44 -0700434 if (isCameraID) {
435 mCurrentModule.onPreviewFocusChanged(false);
Doris Liuaa874422013-09-18 19:43:12 -0700436 CameraActivity.this.setSystemBarsVisibility(true);
ztenghui7b265a62013-09-09 14:58:44 -0700437 }
Mangesh Ghiware33035c12013-08-23 13:28:21 -0700438 hidePanoStitchingProgress();
439 } else {
ztenghui7b265a62013-09-09 14:58:44 -0700440 if (isCameraID) {
Sascha Haeberlinga5a08d72013-09-11 20:30:52 -0700441 // Don't show the action bar in Camera
442 // preview.
Doris Liuaa874422013-09-18 19:43:12 -0700443 CameraActivity.this.setSystemBarsVisibility(false);
Erin Dahlgren3044d8c2013-10-10 18:23:45 -0700444
Doris Liu742cd5b2013-09-12 16:17:43 -0700445 if (mPendingDeletion) {
446 performDeletion();
447 }
Alan Newberger1ef76d42013-09-04 19:01:59 -0700448 } else {
449 updateActionBarMenu(dataID);
450 }
ztenghui2c3d9a52013-09-03 11:27:21 -0700451
Mangesh Ghiware33035c12013-08-23 13:28:21 -0700452 Uri contentUri = currentData.getContentUri();
453 if (contentUri == null) {
454 hidePanoStitchingProgress();
455 return;
456 }
Angus Kong20fad242013-11-11 18:23:46 -0800457 int panoStitchingProgress = mPanoramaManager.getTaskProgress(contentUri);
Mangesh Ghiware33035c12013-08-23 13:28:21 -0700458 if (panoStitchingProgress < 0) {
459 hidePanoStitchingProgress();
460 return;
461 }
462 showPanoStitchingProgress();
463 updateStitchingProgress(panoStitchingProgress);
464 }
ztenghui2c3d9a52013-09-03 11:27:21 -0700465 }
Mangesh Ghiware33035c12013-08-23 13:28:21 -0700466 });
Sascha Haeberling37f36112013-08-06 14:31:52 -0700467 }
Sascha Haeberling394023f2013-08-15 15:57:29 -0700468
469 @Override
Doris Liuaa874422013-09-18 19:43:12 -0700470 public void onToggleSystemDecorsVisibility(int dataID) {
471 // If action bar is showing, hide it immediately, otherwise
472 // show action bar and hide it later
Sascha Haeberling394023f2013-08-15 15:57:29 -0700473 if (mActionBar.isShowing()) {
Doris Liuaa874422013-09-18 19:43:12 -0700474 CameraActivity.this.setSystemBarsVisibility(false);
Sascha Haeberling394023f2013-08-15 15:57:29 -0700475 } else {
ztenghui8566dd72013-09-12 14:56:56 -0700476 // Don't show the action bar if that is the camera preview.
477 boolean isCameraID = isCameraPreview(dataID);
478 if (!isCameraID) {
Doris Liuaa874422013-09-18 19:43:12 -0700479 CameraActivity.this.setSystemBarsVisibility(true, true);
ztenghuifd43e3b2013-09-03 11:30:11 -0700480 }
Sascha Haeberling394023f2013-08-15 15:57:29 -0700481 }
482 }
Doris Liuaa874422013-09-18 19:43:12 -0700483
484 @Override
485 public void setSystemDecorsVisibility(boolean visible) {
486 CameraActivity.this.setSystemBarsVisibility(visible);
487 }
Sascha Haeberling37f36112013-08-06 14:31:52 -0700488 };
489
Sascha Haeberling4ed20592013-09-13 11:58:33 -0700490 public void gotoGallery() {
Seth Raphaelcbd82672013-11-05 10:12:36 -0800491 UsageStatistics.onEvent(UsageStatistics.COMPONENT_CAMERA, UsageStatistics.ACTION_FILMSTRIP,
492 "thumbnailTap");
493
Angus Kong62848152013-11-08 17:25:29 -0800494 mFilmstripController.goToNextItem();
Sascha Haeberling4ed20592013-09-13 11:58:33 -0700495 }
496
Sascha Haeberling5199c202013-09-05 17:10:19 -0700497 /**
Doris Liuaa874422013-09-18 19:43:12 -0700498 * If {@param visible} is false, this hides the action bar and switches the system UI
499 * to lights-out mode.
Sascha Haeberling5199c202013-09-05 17:10:19 -0700500 */
Doris Liu97cb1ea2013-10-11 16:54:51 -0700501 // TODO: This should not be called outside of the activity.
Sascha Haeberling4ec139d2013-10-09 23:46:20 -0700502 public void setSystemBarsVisibility(boolean visible) {
Doris Liuaa874422013-09-18 19:43:12 -0700503 setSystemBarsVisibility(visible, false);
504 }
505
506 /**
507 * If {@param visible} is false, this hides the action bar and switches the
508 * system UI to lights-out mode. If {@param hideLater} is true, a delayed message
509 * will be sent after a timeout to hide the action bar.
510 */
511 private void setSystemBarsVisibility(boolean visible, boolean hideLater) {
512 mMainHandler.removeMessages(HIDE_ACTION_BAR);
Doris Liuaa874422013-09-18 19:43:12 -0700513
ztenghui17f1e652013-11-06 14:20:31 -0800514 int currentSystemUIVisibility = mAboveFilmstripControlLayout.getSystemUiVisibility();
515 int newSystemUIVisibility = DEFAULT_SYSTEM_UI_VISIBILITY |
516 (visible ? View.SYSTEM_UI_FLAG_VISIBLE :
517 View.SYSTEM_UI_FLAG_LOW_PROFILE | View.SYSTEM_UI_FLAG_FULLSCREEN);
518 if (newSystemUIVisibility != currentSystemUIVisibility) {
519 mAboveFilmstripControlLayout.setSystemUiVisibility(newSystemUIVisibility);
520 }
Doris Liu97cb1ea2013-10-11 16:54:51 -0700521
ztenghui17f1e652013-11-06 14:20:31 -0800522 boolean currentActionBarVisibility = mActionBar.isShowing();
523 if (visible != currentActionBarVisibility) {
Doris Liuaa874422013-09-18 19:43:12 -0700524 if (visible) {
525 mActionBar.show();
526 } else {
527 mActionBar.hide();
528 }
529 if (mOnActionBarVisibilityListener != null) {
530 mOnActionBarVisibilityListener.onActionBarVisibilityChanged(visible);
531 }
532 }
533
534 // Now delay hiding the bars
535 if (visible && hideLater) {
536 mMainHandler.sendEmptyMessageDelayed(HIDE_ACTION_BAR, SHOW_ACTION_BAR_TIMEOUT_MS);
Sascha Haeberling5199c202013-09-05 17:10:19 -0700537 }
Sascha Haeberling5199c202013-09-05 17:10:19 -0700538 }
539
Sascha Haeberling37f36112013-08-06 14:31:52 -0700540 private void hidePanoStitchingProgress() {
541 mPanoStitchingPanel.setVisibility(View.GONE);
542 }
543
544 private void showPanoStitchingProgress() {
545 mPanoStitchingPanel.setVisibility(View.VISIBLE);
546 }
547
548 private void updateStitchingProgress(int progress) {
549 mBottomProgress.setProgress(progress);
550 }
Doris Liu6432cd62013-06-13 17:20:31 -0700551
Mangesh Ghiwarea5682ab2013-09-19 09:24:23 -0700552 @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
553 private void setupNfcBeamPush() {
554 NfcAdapter adapter = NfcAdapter.getDefaultAdapter(CameraActivity.this);
555 if (adapter == null) {
556 return;
557 }
558
559 if (!ApiHelper.HAS_SET_BEAM_PUSH_URIS) {
560 // Disable beaming
561 adapter.setNdefPushMessage(null, CameraActivity.this);
562 return;
563 }
564
565 adapter.setBeamPushUris(null, CameraActivity.this);
566 adapter.setBeamPushUrisCallback(new CreateBeamUrisCallback() {
567 @Override
568 public Uri[] createBeamUris(NfcEvent event) {
569 return mNfcPushUris;
570 }
571 }, CameraActivity.this);
572 }
573
574 private void setNfcBeamPushUri(Uri uri) {
575 mNfcPushUris[0] = uri;
576 }
577
Mangesh Ghiwarecd2eeb02013-08-23 13:28:21 -0700578 private void setStandardShareIntent(Uri contentUri, String mimeType) {
ztenghui05804752013-09-17 11:33:02 -0700579 mStandardShareIntent = getShareIntentFromType(mimeType);
580 if (mStandardShareIntent != null) {
581 mStandardShareIntent.putExtra(Intent.EXTRA_STREAM, contentUri);
582 mStandardShareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
583 if (mStandardShareActionProvider != null) {
584 mStandardShareActionProvider.setShareIntent(mStandardShareIntent);
585 }
Mangesh Ghiwarecd2eeb02013-08-23 13:28:21 -0700586 }
ztenghui05804752013-09-17 11:33:02 -0700587 }
588
589 /**
590 * Get the share intent according to the mimeType
591 *
592 * @param mimeType The mimeType of current data.
593 * @return the video/image's ShareIntent or null if mimeType is invalid.
594 */
595 private Intent getShareIntentFromType(String mimeType) {
596 // Lazily create the intent object.
597 if (mimeType.startsWith("video/")) {
598 if (mVideoShareIntent == null) {
599 mVideoShareIntent = new Intent(Intent.ACTION_SEND);
600 mVideoShareIntent.setType("video/*");
601 }
602 return mVideoShareIntent;
603 } else if (mimeType.startsWith("image/")) {
604 if (mImageShareIntent == null) {
605 mImageShareIntent = new Intent(Intent.ACTION_SEND);
606 mImageShareIntent.setType("image/*");
607 }
608 return mImageShareIntent;
Mangesh Ghiwarecd2eeb02013-08-23 13:28:21 -0700609 }
ztenghui05804752013-09-17 11:33:02 -0700610 Log.w(TAG, "unsupported mimeType " + mimeType);
611 return null;
Mangesh Ghiwarecd2eeb02013-08-23 13:28:21 -0700612 }
613
614 private void setPanoramaShareIntent(Uri contentUri) {
615 if (mPanoramaShareIntent == null) {
616 mPanoramaShareIntent = new Intent(Intent.ACTION_SEND);
617 }
618 mPanoramaShareIntent.setType("application/vnd.google.panorama360+jpg");
619 mPanoramaShareIntent.putExtra(Intent.EXTRA_STREAM, contentUri);
620 if (mPanoramaShareActionProvider != null) {
621 mPanoramaShareActionProvider.setShareIntent(mPanoramaShareIntent);
622 }
623 }
624
Doris Liuaa874422013-09-18 19:43:12 -0700625 @Override
626 public void onMenuVisibilityChanged(boolean isVisible) {
627 // If menu is showing, we need to make sure action bar does not go away.
628 mMainHandler.removeMessages(HIDE_ACTION_BAR);
629 if (!isVisible) {
630 mMainHandler.sendEmptyMessageDelayed(HIDE_ACTION_BAR, SHOW_ACTION_BAR_TIMEOUT_MS);
631 }
632 }
633
Seth Raphaelcbd82672013-11-05 10:12:36 -0800634 @Override
635 public boolean onShareTargetSelected(ShareActionProvider shareActionProvider, Intent intent) {
Angus Kong62848152013-11-08 17:25:29 -0800636 int currentDataId = mFilmstripController.getCurrentId();
Seth Raphaelcbd82672013-11-05 10:12:36 -0800637 if (currentDataId < 0) {
638 return false;
639 }
640 UsageStatistics.onEvent(UsageStatistics.COMPONENT_CAMERA, UsageStatistics.ACTION_SHARE,
641 intent.getComponent().getPackageName(), 0,
642 UsageStatistics.hashFileName(fileNameFromDataID(currentDataId)));
643 return true;
644 }
645
ztenghui0353ca22013-08-13 13:53:16 -0700646 /**
647 * According to the data type, make the menu items for supported operations
648 * visible.
Sascha Haeberlinga5a08d72013-09-11 20:30:52 -0700649 *
Sascha Haeberlingfae11a12013-08-15 14:29:49 -0700650 * @param dataID the data ID of the current item.
ztenghui0353ca22013-08-13 13:53:16 -0700651 */
Sascha Haeberlingfae11a12013-08-15 14:29:49 -0700652 private void updateActionBarMenu(int dataID) {
653 LocalData currentData = mDataAdapter.getLocalData(dataID);
Erin Dahlgrend4f69ed2013-10-01 13:42:51 -0700654 if (currentData == null) {
655 return;
656 }
Sascha Haeberlingfae11a12013-08-15 14:29:49 -0700657 int type = currentData.getLocalDataType();
658
ztenghui0353ca22013-08-13 13:53:16 -0700659 if (mActionBarMenu == null) {
660 return;
661 }
662
663 int supported = 0;
Angus Kong32509872013-10-02 16:53:40 -0700664
ztenghui0353ca22013-08-13 13:53:16 -0700665 switch (type) {
666 case LocalData.LOCAL_IMAGE:
667 supported |= SUPPORT_DELETE | SUPPORT_ROTATE | SUPPORT_INFO
668 | SUPPORT_CROP | SUPPORT_SETAS | SUPPORT_EDIT
Mangesh Ghiwarecd2eeb02013-08-23 13:28:21 -0700669 | SUPPORT_SHARE | SUPPORT_SHOW_ON_MAP;
ztenghui0353ca22013-08-13 13:53:16 -0700670 break;
671 case LocalData.LOCAL_VIDEO:
Mangesh Ghiwarecd2eeb02013-08-23 13:28:21 -0700672 supported |= SUPPORT_DELETE | SUPPORT_INFO | SUPPORT_TRIM
673 | SUPPORT_SHARE;
ztenghui0353ca22013-08-13 13:53:16 -0700674 break;
675 case LocalData.LOCAL_PHOTO_SPHERE:
676 supported |= SUPPORT_DELETE | SUPPORT_ROTATE | SUPPORT_INFO
677 | SUPPORT_CROP | SUPPORT_SETAS | SUPPORT_EDIT
Mangesh Ghiwarecd2eeb02013-08-23 13:28:21 -0700678 | SUPPORT_SHARE | SUPPORT_SHOW_ON_MAP;
679 break;
680 case LocalData.LOCAL_360_PHOTO_SPHERE:
681 supported |= SUPPORT_DELETE | SUPPORT_ROTATE | SUPPORT_INFO
682 | SUPPORT_CROP | SUPPORT_SETAS | SUPPORT_EDIT
683 | SUPPORT_SHARE | SUPPORT_SHARE_PANORAMA360
ztenghui0353ca22013-08-13 13:53:16 -0700684 | SUPPORT_SHOW_ON_MAP;
685 break;
686 default:
687 break;
688 }
689
ztenghuie941cbe2013-10-02 17:31:47 -0700690 // In secure camera mode, we only support delete operation.
691 if (isSecureCamera()) {
692 supported &= SUPPORT_DELETE;
693 }
694
ztenghui0353ca22013-08-13 13:53:16 -0700695 setMenuItemVisible(mActionBarMenu, R.id.action_delete,
696 (supported & SUPPORT_DELETE) != 0);
697 setMenuItemVisible(mActionBarMenu, R.id.action_rotate_ccw,
698 (supported & SUPPORT_ROTATE) != 0);
699 setMenuItemVisible(mActionBarMenu, R.id.action_rotate_cw,
700 (supported & SUPPORT_ROTATE) != 0);
Mangesh Ghiwarecd2eeb02013-08-23 13:28:21 -0700701 setMenuItemVisible(mActionBarMenu, R.id.action_details,
702 (supported & SUPPORT_INFO) != 0);
ztenghui0353ca22013-08-13 13:53:16 -0700703 setMenuItemVisible(mActionBarMenu, R.id.action_crop,
704 (supported & SUPPORT_CROP) != 0);
ztenghui0353ca22013-08-13 13:53:16 -0700705 setMenuItemVisible(mActionBarMenu, R.id.action_setas,
706 (supported & SUPPORT_SETAS) != 0);
ztenghui0353ca22013-08-13 13:53:16 -0700707 setMenuItemVisible(mActionBarMenu, R.id.action_edit,
708 (supported & SUPPORT_EDIT) != 0);
Mangesh Ghiwarecd2eeb02013-08-23 13:28:21 -0700709 setMenuItemVisible(mActionBarMenu, R.id.action_trim,
710 (supported & SUPPORT_TRIM) != 0);
711
Mangesh Ghiware33035c12013-08-23 13:28:21 -0700712 boolean standardShare = (supported & SUPPORT_SHARE) != 0;
713 boolean panoramaShare = (supported & SUPPORT_SHARE_PANORAMA360) != 0;
714 setMenuItemVisible(mActionBarMenu, R.id.action_share, standardShare);
715 setMenuItemVisible(mActionBarMenu, R.id.action_share_panorama, panoramaShare);
716
717 if (panoramaShare) {
718 // For 360 PhotoSphere, relegate standard share to the overflow menu
719 MenuItem item = mActionBarMenu.findItem(R.id.action_share);
720 if (item != null) {
721 item.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
722 item.setTitle(getResources().getString(R.string.share_as_photo));
723 }
724 // And, promote "share as panorama" to action bar
725 item = mActionBarMenu.findItem(R.id.action_share_panorama);
726 if (item != null) {
727 item.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
728 }
Mangesh Ghiwarecd2eeb02013-08-23 13:28:21 -0700729 setPanoramaShareIntent(currentData.getContentUri());
730 }
Mangesh Ghiware33035c12013-08-23 13:28:21 -0700731 if (standardShare) {
732 if (!panoramaShare) {
733 MenuItem item = mActionBarMenu.findItem(R.id.action_share);
734 if (item != null) {
735 item.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
736 item.setTitle(getResources().getString(R.string.share));
737 }
738 }
739 setStandardShareIntent(currentData.getContentUri(), currentData.getMimeType());
Mangesh Ghiwarea5682ab2013-09-19 09:24:23 -0700740 setNfcBeamPushUri(currentData.getContentUri());
Mangesh Ghiware33035c12013-08-23 13:28:21 -0700741 }
Sascha Haeberlingfae11a12013-08-15 14:29:49 -0700742
743 boolean itemHasLocation = currentData.getLatLong() != null;
744 setMenuItemVisible(mActionBarMenu, R.id.action_show_on_map,
745 itemHasLocation && (supported & SUPPORT_SHOW_ON_MAP) != 0);
ztenghui0353ca22013-08-13 13:53:16 -0700746 }
747
748 private void setMenuItemVisible(Menu menu, int itemId, boolean visible) {
749 MenuItem item = menu.findItem(itemId);
Angus Kong20fad242013-11-11 18:23:46 -0800750 if (item != null) {
ztenghui0353ca22013-08-13 13:53:16 -0700751 item.setVisible(visible);
Angus Kong20fad242013-11-11 18:23:46 -0800752 }
ztenghui0353ca22013-08-13 13:53:16 -0700753 }
754
Ruben Brunk7cfcafd2013-10-17 15:41:44 -0700755 private ImageTaskManager.TaskListener mPlaceholderListener =
756 new ImageTaskManager.TaskListener() {
757
758 @Override
759 public void onTaskQueued(String filePath, final Uri imageUri) {
760 mMainHandler.post(new Runnable() {
761 @Override
762 public void run() {
763 notifyNewMedia(imageUri);
764 int dataID = mDataAdapter.findDataByContentUri(imageUri);
765 if (dataID != -1) {
766 LocalData d = mDataAdapter.getLocalData(dataID);
767 InProgressDataWrapper newData = new InProgressDataWrapper(d, true);
768 mDataAdapter.updateData(dataID, newData);
769 }
770 }
771 });
772 }
773
774 @Override
775 public void onTaskDone(String filePath, final Uri imageUri) {
776 mMainHandler.post(new Runnable() {
777 @Override
778 public void run() {
779 mDataAdapter.refresh(getContentResolver(), imageUri);
780 }
781 });
782 }
783
784 @Override
785 public void onTaskProgress(String filePath, Uri imageUri, int progress) {
786 // Do nothing
787 }
Angus Kong20fad242013-11-11 18:23:46 -0800788 };
Ruben Brunk7cfcafd2013-10-17 15:41:44 -0700789
Angus Kong6798c342013-07-16 15:14:58 -0700790 private ImageTaskManager.TaskListener mStitchingListener =
791 new ImageTaskManager.TaskListener() {
792 @Override
Sascha Haeberling37f36112013-08-06 14:31:52 -0700793 public void onTaskQueued(String filePath, final Uri imageUri) {
794 mMainHandler.post(new Runnable() {
795 @Override
796 public void run() {
797 notifyNewMedia(imageUri);
Angus Kong32509872013-10-02 16:53:40 -0700798 int dataID = mDataAdapter.findDataByContentUri(imageUri);
799 if (dataID != -1) {
800 // Don't allow special UI actions (swipe to
801 // delete, for example) on in-progress data.
802 LocalData d = mDataAdapter.getLocalData(dataID);
803 InProgressDataWrapper newData = new InProgressDataWrapper(d);
804 mDataAdapter.updateData(dataID, newData);
805 }
Sascha Haeberling37f36112013-08-06 14:31:52 -0700806 }
807 });
Angus Kong6798c342013-07-16 15:14:58 -0700808 }
809
810 @Override
Sascha Haeberling37f36112013-08-06 14:31:52 -0700811 public void onTaskDone(String filePath, final Uri imageUri) {
812 Log.v(TAG, "onTaskDone:" + filePath);
813 mMainHandler.post(new Runnable() {
814 @Override
815 public void run() {
816 int doneID = mDataAdapter.findDataByContentUri(imageUri);
Angus Kong62848152013-11-08 17:25:29 -0800817 int currentDataId = mFilmstripController.getCurrentId();
Sascha Haeberling37f36112013-08-06 14:31:52 -0700818
819 if (currentDataId == doneID) {
820 hidePanoStitchingProgress();
821 updateStitchingProgress(0);
822 }
823
824 mDataAdapter.refresh(getContentResolver(), imageUri);
825 }
826 });
Angus Kong6798c342013-07-16 15:14:58 -0700827 }
828
829 @Override
830 public void onTaskProgress(
Sascha Haeberling37f36112013-08-06 14:31:52 -0700831 String filePath, final Uri imageUri, final int progress) {
832 mMainHandler.post(new Runnable() {
833 @Override
834 public void run() {
Angus Kong62848152013-11-08 17:25:29 -0800835 int currentDataId = mFilmstripController.getCurrentId();
Sascha Haeberling37f36112013-08-06 14:31:52 -0700836 if (currentDataId == -1) {
837 return;
838 }
839 if (imageUri.equals(
840 mDataAdapter.getLocalData(currentDataId).getContentUri())) {
841 updateStitchingProgress(progress);
842 }
843 }
844 });
Angus Kong6798c342013-07-16 15:14:58 -0700845 }
846 };
847
Angus Kong9f1db522013-11-09 16:25:59 -0800848 @Override
849 public Context getAndroidContext() {
850 return this;
851 }
852
853 @Override
854 public SurfaceTexture getPreviewBuffer() {
855 // TODO: implement this
856 return null;
857 }
858
859 @Override
860 public FrameLayout getModuleLayoutRoot() {
861 return mCameraModuleRootView;
862 }
863
864 @Override
865 public void setShutterEventsListener(ShutterEventsListener listener) {
866 // TODO: implement this
867 }
868
869 @Override
870 public void setShutterEnabled(boolean enabled) {
871 // TODO: implement this
872 }
873
874 @Override
875 public boolean isShutterEnabled() {
876 // TODO: implement this
877 return false;
878 }
879
880 @Override
881 public void startPreCaptureAnimation() {
882 // TODO: implement this
883 }
884
885 @Override
886 public void cancelPreCaptureAnimation() {
887 // TODO: implement this
888 }
889
890 @Override
891 public void startPostCaptureAnimation() {
892 // TODO: implement this
893 }
894
895 @Override
896 public void startPostCaptureAnimation(Bitmap thumbnail) {
897 // TODO: implement this
898 }
899
900 @Override
901 public void cancelPostCaptureAnimation() {
902 // TODO: implement this
903 }
904
905 @Override
Angus Kongfd4fc0e2013-11-07 15:38:09 -0800906 public MediaSaver getMediaSaver() {
907 return mMediaSaver;
Michael Kolb8872c232013-01-29 10:33:22 -0800908 }
909
Angus Kong9f1db522013-11-09 16:25:59 -0800910 @Override
911 public OrientationManager getOrientationManager() {
912 return mOrientationManager;
913 }
914
915 @Override
916 public LocationManager getLocationManager() {
917 // TODO: implement this
918 return null;
919 }
920
921 @Override
922 public void lockOrientation() {
923 mOrientationManager.lockOrientation();
924 }
925
926 @Override
927 public void unlockOrientation() {
928 mOrientationManager.unlockOrientation();
929 }
930
931 @Override
Doris Liu6432cd62013-06-13 17:20:31 -0700932 public void notifyNewMedia(Uri uri) {
933 ContentResolver cr = getContentResolver();
934 String mimeType = cr.getType(uri);
935 if (mimeType.startsWith("video/")) {
Angus Kongb50b5cb2013-08-09 14:55:20 -0700936 sendBroadcast(new Intent(CameraUtil.ACTION_NEW_VIDEO, uri));
Doris Liu6432cd62013-06-13 17:20:31 -0700937 mDataAdapter.addNewVideo(cr, uri);
938 } else if (mimeType.startsWith("image/")) {
Angus Kongb50b5cb2013-08-09 14:55:20 -0700939 CameraUtil.broadcastNewPicture(this, uri);
Doris Liu6432cd62013-06-13 17:20:31 -0700940 mDataAdapter.addNewPhoto(cr, uri);
Sascha Haeberling37f36112013-08-06 14:31:52 -0700941 } else if (mimeType.startsWith("application/stitching-preview")) {
942 mDataAdapter.addNewPhoto(cr, uri);
Ruben Brunk7cfcafd2013-10-17 15:41:44 -0700943 } else if (mimeType.startsWith(PlaceholderManager.PLACEHOLDER_MIME_TYPE)) {
944 mDataAdapter.addNewPhoto(cr, uri);
Doris Liu48239f42013-03-04 22:19:10 -0800945 } else {
Doris Liu6432cd62013-06-13 17:20:31 -0700946 android.util.Log.w(TAG, "Unknown new media with MIME type:"
947 + mimeType + ", uri:" + uri);
Doris Liu48239f42013-03-04 22:19:10 -0800948 }
949 }
950
Angus Kong20fad242013-11-11 18:23:46 -0800951 @Override
952 public CameraProvider getCameraProvider() {
953 return mCameraController;
954 }
955
Doris Liu6432cd62013-06-13 17:20:31 -0700956 private void removeData(int dataID) {
957 mDataAdapter.removeData(CameraActivity.this, dataID);
Doris Liu742cd5b2013-09-12 16:17:43 -0700958 if (mDataAdapter.getTotalNumber() > 1) {
959 showUndoDeletionBar();
960 } else {
961 // If camera preview is the only view left in filmstrip,
962 // no need to show undo bar.
Doris Liuf2c14332013-09-26 11:24:37 -0700963 mPendingDeletion = true;
Doris Liu742cd5b2013-09-12 16:17:43 -0700964 performDeletion();
965 }
Michael Kolb8872c232013-01-29 10:33:22 -0800966 }
967
Angus Kong86d36312013-01-31 18:22:44 -0800968 private void bindMediaSaveService() {
969 Intent intent = new Intent(this, MediaSaveService.class);
Angus Kong86d36312013-01-31 18:22:44 -0800970 bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
971 }
972
973 private void unbindMediaSaveService() {
Michael Kolb955e5c52013-03-22 14:11:57 -0700974 if (mConnection != null) {
975 unbindService(mConnection);
976 }
Angus Kong86d36312013-01-31 18:22:44 -0800977 }
978
Michael Kolb8872c232013-01-29 10:33:22 -0800979 @Override
ztenghui0353ca22013-08-13 13:53:16 -0700980 public boolean onCreateOptionsMenu(Menu menu) {
981 // Inflate the menu items for use in the action bar
982 MenuInflater inflater = getMenuInflater();
983 inflater.inflate(R.menu.operations, menu);
984 mActionBarMenu = menu;
Mangesh Ghiwarecd2eeb02013-08-23 13:28:21 -0700985
986 // Configure the standard share action provider
987 MenuItem item = menu.findItem(R.id.action_share);
988 mStandardShareActionProvider = (ShareActionProvider) item.getActionProvider();
Mangesh Ghiware33035c12013-08-23 13:28:21 -0700989 mStandardShareActionProvider.setShareHistoryFileName("standard_share_history.xml");
Mangesh Ghiwarecd2eeb02013-08-23 13:28:21 -0700990 if (mStandardShareIntent != null) {
991 mStandardShareActionProvider.setShareIntent(mStandardShareIntent);
992 }
993
994 // Configure the panorama share action provider
995 item = menu.findItem(R.id.action_share_panorama);
996 mPanoramaShareActionProvider = (ShareActionProvider) item.getActionProvider();
Mangesh Ghiware33035c12013-08-23 13:28:21 -0700997 mPanoramaShareActionProvider.setShareHistoryFileName("panorama_share_history.xml");
Mangesh Ghiwarecd2eeb02013-08-23 13:28:21 -0700998 if (mPanoramaShareIntent != null) {
999 mPanoramaShareActionProvider.setShareIntent(mPanoramaShareIntent);
1000 }
1001
Seth Raphaelcbd82672013-11-05 10:12:36 -08001002 mStandardShareActionProvider.setOnShareTargetSelectedListener(this);
1003 mPanoramaShareActionProvider.setOnShareTargetSelectedListener(this);
1004
ztenghui0353ca22013-08-13 13:53:16 -07001005 return super.onCreateOptionsMenu(menu);
1006 }
1007
1008 @Override
1009 public boolean onOptionsItemSelected(MenuItem item) {
Angus Kong62848152013-11-08 17:25:29 -08001010 int currentDataId = mFilmstripController.getCurrentId();
Sascha Haeberling6f64b502013-08-14 16:23:18 -07001011 if (currentDataId < 0) {
1012 return false;
1013 }
1014 final LocalData localData = mDataAdapter.getLocalData(currentDataId);
1015
ztenghui0353ca22013-08-13 13:53:16 -07001016 // Handle presses on the action bar items
1017 switch (item.getItemId()) {
Alan Newberger3f969c12013-08-23 10:10:30 -07001018 case android.R.id.home:
1019 // ActionBar's Up/Home button was clicked
Mangesh Ghiware30968d02013-10-02 14:38:12 -07001020 try {
Alan Newberger761306f2013-10-30 12:51:21 -07001021 startActivity(IntentHelper.getGalleryIntent(this));
Mangesh Ghiware30968d02013-10-02 14:38:12 -07001022 return true;
1023 } catch (ActivityNotFoundException e) {
Alan Newberger761306f2013-10-30 12:51:21 -07001024 Log.w(TAG, "Failed to launch gallery activity, closing");
Mangesh Ghiware30968d02013-10-02 14:38:12 -07001025 finish();
Mangesh Ghiware5df64b02013-09-18 18:25:26 -07001026 }
ztenghui0353ca22013-08-13 13:53:16 -07001027 case R.id.action_delete:
Seth Raphaelcbd82672013-11-05 10:12:36 -08001028 UsageStatistics.onEvent(UsageStatistics.COMPONENT_CAMERA,
1029 UsageStatistics.ACTION_DELETE, null, 0,
1030 UsageStatistics.hashFileName(fileNameFromDataID(currentDataId)));
Angus Konge857cc92013-08-19 14:46:20 -07001031 removeData(currentDataId);
ztenghui0353ca22013-08-13 13:53:16 -07001032 return true;
1033 case R.id.action_edit:
Seth Raphaelcbd82672013-11-05 10:12:36 -08001034 UsageStatistics.onEvent(UsageStatistics.COMPONENT_CAMERA,
1035 UsageStatistics.ACTION_EDIT, null, 0,
1036 UsageStatistics.hashFileName(fileNameFromDataID(currentDataId)));
Sascha Haeberling88ef7662013-08-15 17:19:22 -07001037 launchEditor(localData);
ztenghui0353ca22013-08-13 13:53:16 -07001038 return true;
nicolasroard08193042013-08-20 09:19:23 -07001039 case R.id.action_trim: {
ztenghui6b920322013-08-16 16:21:22 -07001040 // This is going to be handled by the Gallery app.
1041 Intent intent = new Intent(ACTION_TRIM_VIDEO);
Angus Kong62848152013-11-08 17:25:29 -08001042 LocalData currentData = mDataAdapter.getLocalData(mFilmstripController.getCurrentId());
ztenghui6b920322013-08-16 16:21:22 -07001043 intent.setData(currentData.getContentUri());
1044 // We need the file path to wrap this into a RandomAccessFile.
1045 intent.putExtra(MEDIA_ITEM_PATH, currentData.getPath());
Sascha Haeberlingb7639c62013-09-09 14:42:43 -07001046 startActivityForResult(intent, REQ_CODE_DONT_SWITCH_TO_PREVIEW);
ztenghui0353ca22013-08-13 13:53:16 -07001047 return true;
nicolasroard08193042013-08-20 09:19:23 -07001048 }
ztenghui0353ca22013-08-13 13:53:16 -07001049 case R.id.action_rotate_ccw:
ztenghuia16e7b52013-08-23 11:47:56 -07001050 localData.rotate90Degrees(this, mDataAdapter, currentDataId, false);
ztenghui0353ca22013-08-13 13:53:16 -07001051 return true;
1052 case R.id.action_rotate_cw:
ztenghuia16e7b52013-08-23 11:47:56 -07001053 localData.rotate90Degrees(this, mDataAdapter, currentDataId, true);
ztenghui0353ca22013-08-13 13:53:16 -07001054 return true;
nicolasroard19ab7252013-09-18 16:54:05 -07001055 case R.id.action_crop: {
Seth Raphaelcbd82672013-11-05 10:12:36 -08001056 UsageStatistics.onEvent(UsageStatistics.COMPONENT_CAMERA,
1057 UsageStatistics.ACTION_CROP, null, 0,
1058 UsageStatistics.hashFileName(fileNameFromDataID(currentDataId)));
nicolasroard19ab7252013-09-18 16:54:05 -07001059 Intent intent = new Intent(CropActivity.CROP_ACTION);
1060 intent.setClass(this, CropActivity.class);
1061 intent.setDataAndType(localData.getContentUri(), localData.getMimeType())
1062 .setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
1063 startActivityForResult(intent, REQ_CODE_DONT_SWITCH_TO_PREVIEW);
ztenghui0353ca22013-08-13 13:53:16 -07001064 return true;
nicolasroard19ab7252013-09-18 16:54:05 -07001065 }
nicolasroard08193042013-08-20 09:19:23 -07001066 case R.id.action_setas: {
1067 Intent intent = new Intent(Intent.ACTION_ATTACH_DATA)
1068 .setDataAndType(localData.getContentUri(),
1069 localData.getMimeType())
1070 .setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
1071 intent.putExtra("mimeType", intent.getType());
Sascha Haeberlingb7639c62013-09-09 14:42:43 -07001072 startActivityForResult(Intent.createChooser(
1073 intent, getString(R.string.set_as)), REQ_CODE_DONT_SWITCH_TO_PREVIEW);
ztenghui0353ca22013-08-13 13:53:16 -07001074 return true;
nicolasroard08193042013-08-20 09:19:23 -07001075 }
ztenghui0353ca22013-08-13 13:53:16 -07001076 case R.id.action_details:
Sascha Haeberling6f64b502013-08-14 16:23:18 -07001077 (new AsyncTask<Void, Void, MediaDetails>() {
1078 @Override
1079 protected MediaDetails doInBackground(Void... params) {
1080 return localData.getMediaDetails(CameraActivity.this);
1081 }
1082
1083 @Override
1084 protected void onPostExecute(MediaDetails mediaDetails) {
Sascha Haeberling64cea6a2013-10-10 20:12:07 -07001085 if (mediaDetails != null) {
1086 DetailsDialog.create(CameraActivity.this, mediaDetails).show();
1087 }
Sascha Haeberling6f64b502013-08-14 16:23:18 -07001088 }
1089 }).execute();
ztenghui0353ca22013-08-13 13:53:16 -07001090 return true;
1091 case R.id.action_show_on_map:
Sascha Haeberlingfae11a12013-08-15 14:29:49 -07001092 double[] latLong = localData.getLatLong();
1093 if (latLong != null) {
Sascha Haeberlinga5a08d72013-09-11 20:30:52 -07001094 CameraUtil.showOnMap(this, latLong);
Sascha Haeberlingfae11a12013-08-15 14:29:49 -07001095 }
ztenghui0353ca22013-08-13 13:53:16 -07001096 return true;
1097 default:
1098 return super.onOptionsItemSelected(item);
1099 }
1100 }
1101
ztenghuifd43e3b2013-09-03 11:30:11 -07001102 private boolean isCaptureIntent() {
1103 if (MediaStore.ACTION_VIDEO_CAPTURE.equals(getIntent().getAction())
1104 || MediaStore.ACTION_IMAGE_CAPTURE.equals(getIntent().getAction())
1105 || MediaStore.ACTION_IMAGE_CAPTURE_SECURE.equals(getIntent().getAction())) {
1106 return true;
1107 } else {
1108 return false;
1109 }
1110 }
1111
ztenghui0353ca22013-08-13 13:53:16 -07001112 @Override
Doris Liu6432cd62013-06-13 17:20:31 -07001113 public void onCreate(Bundle state) {
1114 super.onCreate(state);
Sascha Haeberling048bf4d2013-10-06 17:49:51 -07001115 GcamHelper.init(getContentResolver());
1116
ztenghui50df4702013-08-13 15:53:57 -07001117 getWindow().requestFeature(Window.FEATURE_ACTION_BAR);
Doris Liu1c94b7d2013-11-09 19:13:44 -08001118 setContentView(R.layout.activity_main);
ztenghuifa9e2cc2013-08-09 17:37:15 -07001119 mActionBar = getActionBar();
Doris Liuaa874422013-09-18 19:43:12 -07001120 mActionBar.addOnMenuVisibilityListener(this);
Angus Kong20fad242013-11-11 18:23:46 -08001121 mMainHandler = new MainHandler(getMainLooper());
1122 mCameraController =
1123 new CameraController(this, this, mMainHandler,
1124 CameraManagerFactory.getAndroidCameraManager());
1125 // TODO: Try to move all the resources allocation to happen as soon as
1126 // possible so we can call module.init() at the earliest time.
1127 mModuleManager = new ModuleManagerImpl();
1128 setupModules();
ztenghuifa9e2cc2013-08-09 17:37:15 -07001129
Doris Liu1c94b7d2013-11-09 19:13:44 -08001130 ModeListView modeListView = (ModeListView) findViewById(R.id.mode_list_layout);
1131 if (modeListView != null) {
1132 modeListView.setModeSwitchListener(this);
1133 } else {
1134 Log.e(TAG, "Cannot find mode list in the view hierarchy");
1135 }
1136
Michael Kolb08650182013-02-25 19:43:56 -08001137 if (ApiHelper.HAS_ROTATION_ANIMATION) {
Doris Liu6432cd62013-06-13 17:20:31 -07001138 setRotationAnimation();
Michael Kolb08650182013-02-25 19:43:56 -08001139 }
Doris Liuaa874422013-09-18 19:43:12 -07001140
Doris Liu6432cd62013-06-13 17:20:31 -07001141 // Check if this is in the secure camera mode.
1142 Intent intent = getIntent();
1143 String action = intent.getAction();
Doris Liub84b9732013-06-18 17:14:26 -07001144 if (INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE.equals(action)
1145 || ACTION_IMAGE_CAPTURE_SECURE.equals(action)) {
Doris Liu6432cd62013-06-13 17:20:31 -07001146 mSecureCamera = true;
1147 } else {
1148 mSecureCamera = intent.getBooleanExtra(SECURE_CAMERA_EXTRA, false);
1149 }
Doris Liub84b9732013-06-18 17:14:26 -07001150
1151 if (mSecureCamera) {
1152 // Change the window flags so that secure camera can show when locked
1153 Window win = getWindow();
1154 WindowManager.LayoutParams params = win.getAttributes();
1155 params.flags |= WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
1156 win.setAttributes(params);
1157
1158 // Filter for screen off so that we can finish secure camera activity
1159 // when screen is off.
Doris Liu6432cd62013-06-13 17:20:31 -07001160 IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_OFF);
1161 registerReceiver(mScreenOffReceiver, filter);
Angus Kong6a8e8a12013-07-19 14:55:07 -07001162 // TODO: This static screen off event receiver is a workaround to the
1163 // double onResume() invocation (onResume->onPause->onResume). We should
1164 // find a better solution to this.
1165 if (sScreenOffReceiver == null) {
1166 sScreenOffReceiver = new ScreenOffReceiver();
1167 registerReceiver(sScreenOffReceiver, filter);
1168 }
Doris Liub84b9732013-06-18 17:14:26 -07001169 }
Angus Kong653c43b2013-08-21 18:28:43 -07001170 mAboveFilmstripControlLayout =
1171 (FrameLayout) findViewById(R.id.camera_above_filmstrip_layout);
1172 mAboveFilmstripControlLayout.setFitsSystemWindows(true);
Sascha Haeberling5199c202013-09-05 17:10:19 -07001173 // Hide action bar first since we are in full screen mode first, and
1174 // switch the system UI to lights-out mode.
Doris Liuaa874422013-09-18 19:43:12 -07001175 this.setSystemBarsVisibility(false);
Angus Konged15d1a2013-08-19 15:06:12 -07001176 mPanoramaManager = AppManagerFactory.getInstance(this)
1177 .getPanoramaStitchingManager();
Ruben Brunk7cfcafd2013-10-17 15:41:44 -07001178 mPlaceholderManager = AppManagerFactory.getInstance(this)
1179 .getGcamProcessingManager();
Angus Kong6798c342013-07-16 15:14:58 -07001180 mPanoramaManager.addTaskListener(mStitchingListener);
Ruben Brunk7cfcafd2013-10-17 15:41:44 -07001181 mPlaceholderManager.addTaskListener(mPlaceholderListener);
Doris Liu6432cd62013-06-13 17:20:31 -07001182 LayoutInflater inflater = getLayoutInflater();
1183 View rootLayout = inflater.inflate(R.layout.camera, null, false);
Angus Kong9f1db522013-11-09 16:25:59 -08001184 mCameraModuleRootView = (FrameLayout) rootLayout.findViewById(R.id.camera_app_root);
ztenghuifa9e2cc2013-08-09 17:37:15 -07001185 mPanoStitchingPanel = findViewById(R.id.pano_stitching_progress_panel);
Sascha Haeberling37f36112013-08-06 14:31:52 -07001186 mBottomProgress = (ProgressBar) findViewById(R.id.pano_stitching_progress_bar);
Angus Kong8e5e4ee2013-07-30 11:36:00 -07001187 mCameraPreviewData = new CameraPreviewData(rootLayout,
Angus Kong62848152013-11-08 17:25:29 -08001188 FilmstripImageData.SIZE_FULL,
1189 FilmstripImageData.SIZE_FULL);
Sascha Haeberling37f36112013-08-06 14:31:52 -07001190 // Put a CameraPreviewData at the first position.
Angus Kong8e5e4ee2013-07-30 11:36:00 -07001191 mWrappedDataAdapter = new FixedFirstDataAdapter(
1192 new CameraDataAdapter(new ColorDrawable(
1193 getResources().getColor(R.color.photo_placeholder))),
1194 mCameraPreviewData);
Angus Kong62848152013-11-08 17:25:29 -08001195 mFilmstripController = ((FilmstripView) findViewById(R.id.filmstrip_view)).getController();
1196 mFilmstripController.setViewGap(
Doris Liu6432cd62013-06-13 17:20:31 -07001197 getResources().getDimensionPixelSize(R.dimen.camera_film_strip_gap));
Sascha Haeberlingf1f51862013-07-31 11:28:21 -07001198 mPanoramaViewHelper = new PanoramaViewHelper(this);
1199 mPanoramaViewHelper.onCreate();
Angus Kong62848152013-11-08 17:25:29 -08001200 mFilmstripController.setPanoramaViewHelper(mPanoramaViewHelper);
Doris Liu6432cd62013-06-13 17:20:31 -07001201 // Set up the camera preview first so the preview shows up ASAP.
Angus Kong62848152013-11-08 17:25:29 -08001202 mFilmstripController.setListener(mFilmStripListener);
Sascha Haeberling2654dd92013-08-28 15:28:57 -07001203
1204 int moduleIndex = -1;
Doris Liu2a7f44c2013-08-12 15:18:53 -07001205 if (MediaStore.INTENT_ACTION_VIDEO_CAMERA.equals(getIntent().getAction())
1206 || MediaStore.ACTION_VIDEO_CAPTURE.equals(getIntent().getAction())) {
Doris Liu1c94b7d2013-11-09 19:13:44 -08001207 moduleIndex = ModeListView.MODE_VIDEO;
Sascha Haeberling2654dd92013-08-28 15:28:57 -07001208 } else if (MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA.equals(getIntent().getAction())
1209 || MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE.equals(getIntent()
Ruben Brunkbaffb732013-11-11 14:13:59 -08001210 .getAction())) {
Doris Liu1c94b7d2013-11-09 19:13:44 -08001211 moduleIndex = ModeListView.MODE_PHOTO;
Ruben Brunkbaffb732013-11-11 14:13:59 -08001212 SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
1213 if (prefs.getInt(CameraSettings.KEY_STARTUP_MODULE_INDEX, -1)
Doris Liu1c94b7d2013-11-09 19:13:44 -08001214 == ModeListView.MODE_GCAM && GcamHelper.hasGcamCapture()) {
1215 moduleIndex = ModeListView.MODE_GCAM;
Ruben Brunkbaffb732013-11-11 14:13:59 -08001216 }
1217 } else if (MediaStore.ACTION_IMAGE_CAPTURE.equals(getIntent().getAction())
Sascha Haeberling2654dd92013-08-28 15:28:57 -07001218 || MediaStore.ACTION_IMAGE_CAPTURE_SECURE.equals(getIntent().getAction())) {
Doris Liu1c94b7d2013-11-09 19:13:44 -08001219 moduleIndex = ModeListView.MODE_PHOTO;
Doris Liu2a7f44c2013-08-12 15:18:53 -07001220 } else {
Sascha Haeberling2654dd92013-08-28 15:28:57 -07001221 // If the activity has not been started using an explicit intent,
1222 // read the module index from the last time the user changed modes
1223 SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
Angus Kong0fb819b2013-10-08 13:44:19 -07001224 moduleIndex = prefs.getInt(CameraSettings.KEY_STARTUP_MODULE_INDEX, -1);
Doris Liu1c94b7d2013-11-09 19:13:44 -08001225 if ((moduleIndex == ModeListView.MODE_GCAM &&
Sascha Haeberling98f38bb2013-09-24 18:58:34 -07001226 !GcamHelper.hasGcamCapture()) || moduleIndex < 0) {
Doris Liu1c94b7d2013-11-09 19:13:44 -08001227 moduleIndex = ModeListView.MODE_PHOTO;
Sascha Haeberling2654dd92013-08-28 15:28:57 -07001228 }
Doris Liu2a7f44c2013-08-12 15:18:53 -07001229 }
Sascha Haeberling2654dd92013-08-28 15:28:57 -07001230
Angus Kong9f1db522013-11-09 16:25:59 -08001231 mOrientationManager = new OrientationManagerImpl(this);
1232 mOrientationManager.addOnOrientationChangeListener(mMainHandler, this);
Angus Konged15d1a2013-08-19 15:06:12 -07001233 setModuleFromIndex(moduleIndex);
1234 mCurrentModule.init(this, mCameraModuleRootView);
Sascha Haeberling37f36112013-08-06 14:31:52 -07001235
1236 if (!mSecureCamera) {
1237 mDataAdapter = mWrappedDataAdapter;
Angus Kong62848152013-11-08 17:25:29 -08001238 mFilmstripController.setDataAdapter(mDataAdapter);
Angus Konga7194602013-09-06 17:20:15 -07001239 if (!isCaptureIntent()) {
1240 mDataAdapter.requestLoad(getContentResolver());
1241 }
Sascha Haeberling37f36112013-08-06 14:31:52 -07001242 } else {
Sascha Haeberlinga5a08d72013-09-11 20:30:52 -07001243 // Put a lock placeholder as the last image by setting its date to
1244 // 0.
Sascha Haeberling37f36112013-08-06 14:31:52 -07001245 ImageView v = (ImageView) getLayoutInflater().inflate(
1246 R.layout.secure_album_placeholder, null);
Angus Kong690dc472013-09-21 14:48:51 -07001247 v.setOnClickListener(new View.OnClickListener() {
1248 @Override
1249 public void onClick(View view) {
Alan Newberger761306f2013-10-30 12:51:21 -07001250 try {
Seth Raphaelcbd82672013-11-05 10:12:36 -08001251 UsageStatistics.onEvent(UsageStatistics.COMPONENT_CAMERA,
1252 UsageStatistics.ACTION_GALLERY, null);
Alan Newberger761306f2013-10-30 12:51:21 -07001253 startActivity(IntentHelper.getGalleryIntent(CameraActivity.this));
1254 } catch (ActivityNotFoundException e) {
1255 Log.w(TAG, "Failed to launch gallery activity, closing");
1256 }
Angus Kong690dc472013-09-21 14:48:51 -07001257 finish();
1258 }
1259 });
Sascha Haeberling37f36112013-08-06 14:31:52 -07001260 mDataAdapter = new FixedLastDataAdapter(
1261 mWrappedDataAdapter,
Angus Kongbd260692013-08-07 14:52:56 -07001262 new SimpleViewData(
Sascha Haeberling37f36112013-08-06 14:31:52 -07001263 v,
1264 v.getDrawable().getIntrinsicWidth(),
1265 v.getDrawable().getIntrinsicHeight(),
1266 0, 0));
1267 // Flush out all the original data.
1268 mDataAdapter.flush();
Angus Kong62848152013-11-08 17:25:29 -08001269 mFilmstripController.setDataAdapter(mDataAdapter);
Sascha Haeberling37f36112013-08-06 14:31:52 -07001270 }
Mangesh Ghiwarea5682ab2013-09-19 09:24:23 -07001271
1272 setupNfcBeamPush();
ztenghui064d6002013-09-05 15:47:58 -07001273
Doris Liu2b86d872013-09-26 15:23:41 -07001274 mLocalImagesObserver = new LocalMediaObserver();
1275 mLocalVideosObserver = new LocalMediaObserver();
ztenghui064d6002013-09-05 15:47:58 -07001276
1277 getContentResolver().registerContentObserver(
1278 MediaStore.Images.Media.EXTERNAL_CONTENT_URI, true,
1279 mLocalImagesObserver);
1280 getContentResolver().registerContentObserver(
1281 MediaStore.Video.Media.EXTERNAL_CONTENT_URI, true,
1282 mLocalVideosObserver);
Michael Kolb8872c232013-01-29 10:33:22 -08001283 }
1284
Doris Liu6432cd62013-06-13 17:20:31 -07001285 private void setRotationAnimation() {
Michael Kolb08650182013-02-25 19:43:56 -08001286 int rotationAnimation = WindowManager.LayoutParams.ROTATION_ANIMATION_ROTATE;
Doris Liu6432cd62013-06-13 17:20:31 -07001287 rotationAnimation = WindowManager.LayoutParams.ROTATION_ANIMATION_CROSSFADE;
Michael Kolb08650182013-02-25 19:43:56 -08001288 Window win = getWindow();
1289 WindowManager.LayoutParams winParams = win.getAttributes();
1290 winParams.rotationAnimation = rotationAnimation;
1291 win.setAttributes(winParams);
1292 }
1293
Michael Kolb8872c232013-01-29 10:33:22 -08001294 @Override
Michael Kolb8872c232013-01-29 10:33:22 -08001295 public void onUserInteraction() {
1296 super.onUserInteraction();
1297 mCurrentModule.onUserInteraction();
1298 }
1299
1300 @Override
Doris Liu742cd5b2013-09-12 16:17:43 -07001301 public boolean dispatchTouchEvent(MotionEvent ev) {
1302 boolean result = super.dispatchTouchEvent(ev);
1303 if (ev.getActionMasked() == MotionEvent.ACTION_DOWN) {
1304 // Real deletion is postponed until the next user interaction after
1305 // the gesture that triggers deletion. Until real deletion is performed,
1306 // users can click the undo button to bring back the image that they
1307 // chose to delete.
1308 if (mPendingDeletion && !mIsUndoingDeletion) {
Angus Kong20fad242013-11-11 18:23:46 -08001309 performDeletion();
Doris Liu742cd5b2013-09-12 16:17:43 -07001310 }
1311 }
1312 return result;
1313 }
1314
1315 @Override
Doris Liu6432cd62013-06-13 17:20:31 -07001316 public void onPause() {
Doris Liuf2c14332013-09-26 11:24:37 -07001317 // Delete photos that are pending deletion
1318 performDeletion();
Angus Kong20fad242013-11-11 18:23:46 -08001319 // TODO: call mCurrentModule.pause() instead after all the modules
1320 // support pause().
Doris Liu6432cd62013-06-13 17:20:31 -07001321 mCurrentModule.onPauseBeforeSuper();
Angus Kong9f1db522013-11-09 16:25:59 -08001322 mOrientationManager.pause();
Angus Kong20fad242013-11-11 18:23:46 -08001323 // Close the camera and wait for the operation done.
1324 mCameraController.closeCamera();
Doris Liu6432cd62013-06-13 17:20:31 -07001325 super.onPause();
1326 mCurrentModule.onPauseAfterSuper();
Doris Liu2b86d872013-09-26 15:23:41 -07001327
1328 mLocalImagesObserver.setActivityPaused(true);
1329 mLocalVideosObserver.setActivityPaused(true);
Doris Liu6432cd62013-06-13 17:20:31 -07001330 }
1331
1332 @Override
Sascha Haeberlingb7639c62013-09-09 14:42:43 -07001333 protected void onActivityResult(int requestCode, int resultCode, Intent data) {
ztenghui064d6002013-09-05 15:47:58 -07001334 if (requestCode == REQ_CODE_DONT_SWITCH_TO_PREVIEW) {
Sascha Haeberlingb7639c62013-09-09 14:42:43 -07001335 mResetToPreviewOnResume = false;
1336 } else {
1337 super.onActivityResult(requestCode, resultCode, data);
1338 }
1339 }
1340
1341 @Override
Doris Liu6432cd62013-06-13 17:20:31 -07001342 public void onResume() {
Angus Kongce2b9492013-09-05 17:49:06 -07001343 // TODO: Handle this in OrientationManager.
Sascha Haeberlinga5a08d72013-09-11 20:30:52 -07001344 // Auto-rotate off
Doris Liu6432cd62013-06-13 17:20:31 -07001345 if (Settings.System.getInt(getContentResolver(),
Sascha Haeberlinga5a08d72013-09-11 20:30:52 -07001346 Settings.System.ACCELEROMETER_ROTATION, 0) == 0) {
Doris Liu6432cd62013-06-13 17:20:31 -07001347 setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
1348 mAutoRotateScreen = false;
1349 } else {
1350 setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR);
1351 mAutoRotateScreen = true;
1352 }
Seth Raphaelcbd82672013-11-05 10:12:36 -08001353
1354 UsageStatistics.onEvent(UsageStatistics.COMPONENT_CAMERA,
1355 UsageStatistics.ACTION_FOREGROUNDED, this.getClass().getSimpleName());
1356
Angus Kong9f1db522013-11-09 16:25:59 -08001357 mOrientationManager.resume();
Angus Kong20fad242013-11-11 18:23:46 -08001358 // TODO: call mCurrentModule.resume() instead after all the modules
1359 // support resume().
Doris Liu6432cd62013-06-13 17:20:31 -07001360 mCurrentModule.onResumeBeforeSuper();
1361 super.onResume();
1362 mCurrentModule.onResumeAfterSuper();
1363
Angus Kong6798c342013-07-16 15:14:58 -07001364 setSwipingEnabled(true);
Sascha Haeberlingb7639c62013-09-09 14:42:43 -07001365
1366 if (mResetToPreviewOnResume) {
1367 // Go to the preview on resume.
Angus Kong62848152013-11-08 17:25:29 -08001368 mFilmstripController.goToFirstItem();
Sascha Haeberlingb7639c62013-09-09 14:42:43 -07001369 }
1370 // Default is showing the preview, unless disabled by explicitly
1371 // starting an activity we want to return from to the filmstrip rather
1372 // than the preview.
1373 mResetToPreviewOnResume = true;
ztenghui064d6002013-09-05 15:47:58 -07001374
Doris Liu2b86d872013-09-26 15:23:41 -07001375 if (mLocalVideosObserver.isMediaDataChangedDuringPause()
1376 || mLocalImagesObserver.isMediaDataChangedDuringPause()) {
Angus Kong2d5c7472013-10-12 23:48:46 -07001377 if (!mSecureCamera) {
1378 // If it's secure camera, requestLoad() should not be called
1379 // as it will load all the data.
1380 mDataAdapter.requestLoad(getContentResolver());
1381 }
ztenghui064d6002013-09-05 15:47:58 -07001382 }
Doris Liu2b86d872013-09-26 15:23:41 -07001383 mLocalImagesObserver.setActivityPaused(false);
1384 mLocalVideosObserver.setActivityPaused(false);
Angus Kong6798c342013-07-16 15:14:58 -07001385 }
1386
1387 @Override
1388 public void onStart() {
1389 super.onStart();
Angus Kong7e374eb2013-08-21 11:27:35 -07001390 bindMediaSaveService();
Sascha Haeberlingf1f51862013-07-31 11:28:21 -07001391 mPanoramaViewHelper.onStart();
1392 }
1393
1394 @Override
1395 protected void onStop() {
1396 super.onStop();
1397 mPanoramaViewHelper.onStop();
Angus Kong7e374eb2013-08-21 11:27:35 -07001398 unbindMediaSaveService();
Doris Liu6432cd62013-06-13 17:20:31 -07001399 }
1400
1401 @Override
1402 public void onDestroy() {
Sascha Haeberlinga5a08d72013-09-11 20:30:52 -07001403 if (mSecureCamera) {
1404 unregisterReceiver(mScreenOffReceiver);
1405 }
ztenghui064d6002013-09-05 15:47:58 -07001406 getContentResolver().unregisterContentObserver(mLocalImagesObserver);
1407 getContentResolver().unregisterContentObserver(mLocalVideosObserver);
1408
Doris Liu6432cd62013-06-13 17:20:31 -07001409 super.onDestroy();
1410 }
1411
1412 @Override
1413 public void onConfigurationChanged(Configuration config) {
1414 super.onConfigurationChanged(config);
1415 mCurrentModule.onConfigurationChanged(config);
1416 }
1417
1418 @Override
1419 public boolean onKeyDown(int keyCode, KeyEvent event) {
Angus Kong62848152013-11-08 17:25:29 -08001420 if (mFilmstripController.inCameraFullscreen()) {
Doris Liudba16ae2013-10-03 15:31:40 -07001421 if (mCurrentModule.onKeyDown(keyCode, event)) {
Sascha Haeberlinga5a08d72013-09-11 20:30:52 -07001422 return true;
1423 }
Doris Liudba16ae2013-10-03 15:31:40 -07001424 // Prevent software keyboard or voice search from showing up.
1425 if (keyCode == KeyEvent.KEYCODE_SEARCH
1426 || keyCode == KeyEvent.KEYCODE_MENU) {
1427 if (event.isLongPress()) {
1428 return true;
1429 }
1430 }
Doris Liu6432cd62013-06-13 17:20:31 -07001431 }
Doris Liu6432cd62013-06-13 17:20:31 -07001432
1433 return super.onKeyDown(keyCode, event);
1434 }
1435
1436 @Override
1437 public boolean onKeyUp(int keyCode, KeyEvent event) {
Angus Kong62848152013-11-08 17:25:29 -08001438 if (mFilmstripController.inCameraFullscreen() && mCurrentModule.onKeyUp(keyCode, event)) {
Sascha Haeberlinga5a08d72013-09-11 20:30:52 -07001439 return true;
1440 }
Doris Liu6432cd62013-06-13 17:20:31 -07001441 return super.onKeyUp(keyCode, event);
1442 }
1443
Alan Newberger5f6b50d2013-08-30 15:19:48 -07001444 @Override
1445 public void onBackPressed() {
Angus Kong62848152013-11-08 17:25:29 -08001446 if (!mFilmstripController.inCameraFullscreen()) {
1447 mFilmstripController.goToFirstItem();
Alan Newberger5f6b50d2013-08-30 15:19:48 -07001448 } else if (!mCurrentModule.onBackPressed()) {
1449 super.onBackPressed();
1450 }
1451 }
1452
Doris Liu6432cd62013-06-13 17:20:31 -07001453 public boolean isAutoRotateScreen() {
1454 return mAutoRotateScreen;
1455 }
1456
1457 protected void updateStorageSpace() {
Angus Kong2dcc0a92013-09-25 13:00:08 -07001458 mStorageSpaceBytes = Storage.getAvailableSpace();
Doris Liu6432cd62013-06-13 17:20:31 -07001459 }
1460
Angus Kong2dcc0a92013-09-25 13:00:08 -07001461 protected long getStorageSpaceBytes() {
1462 return mStorageSpaceBytes;
Doris Liu6432cd62013-06-13 17:20:31 -07001463 }
1464
1465 protected void updateStorageSpaceAndHint() {
1466 updateStorageSpace();
Angus Kong2dcc0a92013-09-25 13:00:08 -07001467 updateStorageHint(mStorageSpaceBytes);
Doris Liu6432cd62013-06-13 17:20:31 -07001468 }
1469
1470 protected void updateStorageHint(long storageSpace) {
1471 String message = null;
1472 if (storageSpace == Storage.UNAVAILABLE) {
1473 message = getString(R.string.no_storage);
1474 } else if (storageSpace == Storage.PREPARING) {
1475 message = getString(R.string.preparing_sd);
1476 } else if (storageSpace == Storage.UNKNOWN_SIZE) {
1477 message = getString(R.string.access_sd_fail);
Angus Kong2dcc0a92013-09-25 13:00:08 -07001478 } else if (storageSpace <= Storage.LOW_STORAGE_THRESHOLD_BYTES) {
Doris Liu6432cd62013-06-13 17:20:31 -07001479 message = getString(R.string.spaceIsLow_content);
1480 }
1481
1482 if (message != null) {
1483 if (mStorageHint == null) {
1484 mStorageHint = OnScreenHint.makeText(this, message);
1485 } else {
1486 mStorageHint.setText(message);
1487 }
1488 mStorageHint.show();
1489 } else if (mStorageHint != null) {
1490 mStorageHint.cancel();
1491 mStorageHint = null;
1492 }
1493 }
1494
1495 protected void setResultEx(int resultCode) {
1496 mResultCodeForTesting = resultCode;
1497 setResult(resultCode);
1498 }
1499
1500 protected void setResultEx(int resultCode, Intent data) {
1501 mResultCodeForTesting = resultCode;
1502 mResultDataForTesting = data;
1503 setResult(resultCode, data);
1504 }
1505
1506 public int getResultCode() {
1507 return mResultCodeForTesting;
1508 }
1509
1510 public Intent getResultData() {
1511 return mResultDataForTesting;
1512 }
1513
1514 public boolean isSecureCamera() {
1515 return mSecureCamera;
Michael Kolb8872c232013-01-29 10:33:22 -08001516 }
1517
1518 @Override
Doris Liu1c94b7d2013-11-09 19:13:44 -08001519 public void onModeSelected(int moduleIndex) {
Sascha Haeberlinga5a08d72013-09-11 20:30:52 -07001520 if (mCurrentModuleIndex == moduleIndex) {
1521 return;
1522 }
Doris Liu6432cd62013-06-13 17:20:31 -07001523
Doris Liu6432cd62013-06-13 17:20:31 -07001524 closeModule(mCurrentModule);
Sascha Haeberling2654dd92013-08-28 15:28:57 -07001525 setModuleFromIndex(moduleIndex);
1526
1527 openModule(mCurrentModule);
1528 mCurrentModule.onOrientationChanged(mLastRawOrientation);
Angus Kongfd4fc0e2013-11-07 15:38:09 -08001529 if (mMediaSaver != null) {
1530 mCurrentModule.onMediaSaverAvailable(mMediaSaver);
Sascha Haeberling2654dd92013-08-28 15:28:57 -07001531 }
1532
1533 // Store the module index so we can use it the next time the Camera
1534 // starts up.
1535 SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
Angus Kong0fb819b2013-10-08 13:44:19 -07001536 prefs.edit().putInt(CameraSettings.KEY_STARTUP_MODULE_INDEX, moduleIndex).apply();
Sascha Haeberling2654dd92013-08-28 15:28:57 -07001537 }
1538
1539 /**
Sascha Haeberlinga5a08d72013-09-11 20:30:52 -07001540 * Sets the mCurrentModuleIndex, creates a new module instance for the given
1541 * index an sets it as mCurrentModule.
Sascha Haeberling2654dd92013-08-28 15:28:57 -07001542 */
1543 private void setModuleFromIndex(int moduleIndex) {
Angus Kong20fad242013-11-11 18:23:46 -08001544 ModuleManagerImpl.ModuleAgent agent = mModuleManager.getModuleAgent(moduleIndex);
1545 if (agent == null) {
1546 return;
Doris Liu6432cd62013-06-13 17:20:31 -07001547 }
Angus Kong20fad242013-11-11 18:23:46 -08001548 if (!agent.requestAppForCamera()) {
1549 mCameraController.closeCamera();
1550 }
1551 mCurrentModuleIndex = agent.getModuleId();
1552 mCurrentModule2 = agent.createModule();
1553 mCurrentModule = (CameraModule) mCurrentModule2;
Michael Kolb8872c232013-01-29 10:33:22 -08001554 }
1555
Sascha Haeberling88ef7662013-08-15 17:19:22 -07001556 /**
1557 * Launches an ACTION_EDIT intent for the given local data item.
1558 */
1559 public void launchEditor(LocalData data) {
1560 Intent intent = new Intent(Intent.ACTION_EDIT)
1561 .setDataAndType(data.getContentUri(), data.getMimeType())
1562 .setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
Erin Dahlgren05a04922013-11-07 11:35:10 -08001563 try {
1564 startActivityForResult(intent, REQ_CODE_DONT_SWITCH_TO_PREVIEW);
1565 } catch (ActivityNotFoundException e) {
1566 startActivityForResult(Intent.createChooser(intent, null),
1567 REQ_CODE_DONT_SWITCH_TO_PREVIEW);
1568 }
Sascha Haeberling88ef7662013-08-15 17:19:22 -07001569 }
1570
Sascha Haeberlinga5a08d72013-09-11 20:30:52 -07001571 /**
1572 * Launch the tiny planet editor.
1573 *
Angus Kong20fad242013-11-11 18:23:46 -08001574 * @param data The data must be a 360 degree stereographically mapped
1575 * panoramic image. It will not be modified, instead a new item
1576 * with the result will be added to the filmstrip.
Sascha Haeberlinga5a08d72013-09-11 20:30:52 -07001577 */
1578 public void launchTinyPlanetEditor(LocalData data) {
1579 TinyPlanetFragment fragment = new TinyPlanetFragment();
1580 Bundle bundle = new Bundle();
1581 bundle.putString(TinyPlanetFragment.ARGUMENT_URI, data.getContentUri().toString());
1582 bundle.putString(TinyPlanetFragment.ARGUMENT_TITLE, data.getTitle());
1583 fragment.setArguments(bundle);
1584 fragment.show(getFragmentManager(), "tiny_planet");
1585 }
1586
Doris Liu6432cd62013-06-13 17:20:31 -07001587 private void openModule(CameraModule module) {
Angus Kong653c43b2013-08-21 18:28:43 -07001588 module.init(this, mCameraModuleRootView);
Angus Kong20fad242013-11-11 18:23:46 -08001589 // TODO: call mCurrentModule.resume() instead after all the modules
1590 // support resume().
Doris Liu6432cd62013-06-13 17:20:31 -07001591 module.onResumeBeforeSuper();
1592 module.onResumeAfterSuper();
1593 }
1594
1595 private void closeModule(CameraModule module) {
Angus Kong20fad242013-11-11 18:23:46 -08001596 // TODO: call mCurrentModule.pause() instead after all the modules
1597 // support pause().
Doris Liu6432cd62013-06-13 17:20:31 -07001598 module.onPauseBeforeSuper();
1599 module.onPauseAfterSuper();
Angus Kong653c43b2013-08-21 18:28:43 -07001600 ((ViewGroup) mCameraModuleRootView).removeAllViews();
1601 }
1602
Doris Liu742cd5b2013-09-12 16:17:43 -07001603 private void performDeletion() {
1604 if (!mPendingDeletion) {
1605 return;
1606 }
1607 hideUndoDeletionBar(false);
1608 mDataAdapter.executeDeletion(CameraActivity.this);
Erin Dahlgrenfd7f0a92013-10-21 10:08:54 -07001609
Angus Kong62848152013-11-08 17:25:29 -08001610 int currentId = mFilmstripController.getCurrentId();
Erin Dahlgrenfd7f0a92013-10-21 10:08:54 -07001611 updateActionBarMenu(currentId);
1612 mFilmStripListener.onCurrentDataCentered(currentId);
Doris Liu742cd5b2013-09-12 16:17:43 -07001613 }
1614
1615 public void showUndoDeletionBar() {
1616 if (mPendingDeletion) {
1617 performDeletion();
1618 }
1619 Log.v(TAG, "showing undo bar");
1620 mPendingDeletion = true;
Angus Kong653c43b2013-08-21 18:28:43 -07001621 if (mUndoDeletionBar == null) {
Angus Kong20fad242013-11-11 18:23:46 -08001622 ViewGroup v = (ViewGroup) getLayoutInflater().inflate(R.layout.undo_bar,
1623 mAboveFilmstripControlLayout, true);
Angus Kong653c43b2013-08-21 18:28:43 -07001624 mUndoDeletionBar = (ViewGroup) v.findViewById(R.id.camera_undo_deletion_bar);
1625 View button = mUndoDeletionBar.findViewById(R.id.camera_undo_deletion_button);
1626 button.setOnClickListener(new View.OnClickListener() {
1627 @Override
1628 public void onClick(View view) {
1629 mDataAdapter.undoDataRemoval();
Doris Liu742cd5b2013-09-12 16:17:43 -07001630 hideUndoDeletionBar(true);
1631 }
1632 });
1633 // Setting undo bar clickable to avoid touch events going through
1634 // the bar to the buttons (eg. edit button, etc) underneath the bar.
1635 mUndoDeletionBar.setClickable(true);
1636 // When there is user interaction going on with the undo button, we
1637 // do not want to hide the undo bar.
1638 button.setOnTouchListener(new View.OnTouchListener() {
1639 @Override
1640 public boolean onTouch(View v, MotionEvent event) {
1641 if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
1642 mIsUndoingDeletion = true;
1643 } else if (event.getActionMasked() == MotionEvent.ACTION_UP) {
Angus Kong20fad242013-11-11 18:23:46 -08001644 mIsUndoingDeletion = false;
Doris Liu742cd5b2013-09-12 16:17:43 -07001645 }
1646 return false;
Angus Kong653c43b2013-08-21 18:28:43 -07001647 }
1648 });
1649 }
1650 mUndoDeletionBar.setAlpha(0f);
1651 mUndoDeletionBar.setVisibility(View.VISIBLE);
Doris Liu742cd5b2013-09-12 16:17:43 -07001652 mUndoDeletionBar.animate().setDuration(200).alpha(1f).setListener(null).start();
Angus Kong653c43b2013-08-21 18:28:43 -07001653 }
1654
Doris Liu742cd5b2013-09-12 16:17:43 -07001655 private void hideUndoDeletionBar(boolean withAnimation) {
Angus Kong653c43b2013-08-21 18:28:43 -07001656 Log.v(TAG, "Hiding undo deletion bar");
Doris Liu742cd5b2013-09-12 16:17:43 -07001657 mPendingDeletion = false;
Angus Kong653c43b2013-08-21 18:28:43 -07001658 if (mUndoDeletionBar != null) {
Doris Liu742cd5b2013-09-12 16:17:43 -07001659 if (withAnimation) {
Angus Kong20fad242013-11-11 18:23:46 -08001660 mUndoDeletionBar.animate().setDuration(200).alpha(0f)
Doris Liu742cd5b2013-09-12 16:17:43 -07001661 .setListener(new Animator.AnimatorListener() {
1662 @Override
1663 public void onAnimationStart(Animator animation) {
1664 // Do nothing.
1665 }
1666
1667 @Override
1668 public void onAnimationEnd(Animator animation) {
1669 mUndoDeletionBar.setVisibility(View.GONE);
1670 }
1671
1672 @Override
1673 public void onAnimationCancel(Animator animation) {
1674 // Do nothing.
1675 }
1676
1677 @Override
1678 public void onAnimationRepeat(Animator animation) {
1679 // Do nothing.
1680 }
Angus Kong20fad242013-11-11 18:23:46 -08001681 }).start();
Doris Liu742cd5b2013-09-12 16:17:43 -07001682 } else {
1683 mUndoDeletionBar.setVisibility(View.GONE);
1684 }
Angus Kong653c43b2013-08-21 18:28:43 -07001685 }
Michael Kolb8872c232013-01-29 10:33:22 -08001686 }
1687
1688 @Override
Angus Kong9f1db522013-11-09 16:25:59 -08001689 public void onOrientationChanged(int orientation) {
1690 // We keep the last known orientation. So if the user first orient
1691 // the camera then point the camera to floor or sky, we still have
1692 // the correct orientation.
1693 if (orientation == OrientationManager.ORIENTATION_UNKNOWN) {
1694 return;
1695 }
1696 mLastRawOrientation = orientation;
1697 if (mCurrentModule != null) {
1698 mCurrentModule.onOrientationChanged(orientation);
1699 }
1700 }
1701
Angus Konga7194602013-09-06 17:20:15 -07001702 /**
Sascha Haeberlinga5a08d72013-09-11 20:30:52 -07001703 * Enable/disable swipe-to-filmstrip. Will always disable swipe if in
1704 * capture intent.
Angus Konga7194602013-09-06 17:20:15 -07001705 *
1706 * @param enable {@code true} to enable swipe.
1707 */
Doris Liu6432cd62013-06-13 17:20:31 -07001708 public void setSwipingEnabled(boolean enable) {
Angus Konga7194602013-09-06 17:20:15 -07001709 if (isCaptureIntent()) {
1710 mCameraPreviewData.lockPreview(true);
1711 } else {
1712 mCameraPreviewData.lockPreview(!enable);
1713 }
Michael Kolb8872c232013-01-29 10:33:22 -08001714 }
1715
Erin Dahlgren3044d8c2013-10-10 18:23:45 -07001716
1717 /**
1718 * Check whether camera controls are visible.
1719 *
1720 * @return whether controls are visible.
1721 */
1722 private boolean arePreviewControlsVisible() {
1723 return mCurrentModule.arePreviewControlsVisible();
1724 }
1725
1726 /**
1727 * Show or hide the {@link CameraControls} using the current module's
1728 * implementation of {@link #onPreviewFocusChanged}.
1729 *
1730 * @param showControls whether to show camera controls.
1731 */
1732 private void setPreviewControlsVisibility(boolean showControls) {
1733 mCurrentModule.onPreviewFocusChanged(showControls);
1734 }
1735
Michael Kolb8872c232013-01-29 10:33:22 -08001736 // Accessor methods for getting latency times used in performance testing
1737 public long getAutoFocusTime() {
1738 return (mCurrentModule instanceof PhotoModule) ?
1739 ((PhotoModule) mCurrentModule).mAutoFocusTime : -1;
1740 }
1741
1742 public long getShutterLag() {
1743 return (mCurrentModule instanceof PhotoModule) ?
1744 ((PhotoModule) mCurrentModule).mShutterLag : -1;
1745 }
1746
1747 public long getShutterToPictureDisplayedTime() {
1748 return (mCurrentModule instanceof PhotoModule) ?
1749 ((PhotoModule) mCurrentModule).mShutterToPictureDisplayedTime : -1;
1750 }
1751
1752 public long getPictureDisplayedToJpegCallbackTime() {
1753 return (mCurrentModule instanceof PhotoModule) ?
1754 ((PhotoModule) mCurrentModule).mPictureDisplayedToJpegCallbackTime : -1;
1755 }
1756
1757 public long getJpegCallbackFinishTime() {
1758 return (mCurrentModule instanceof PhotoModule) ?
1759 ((PhotoModule) mCurrentModule).mJpegCallbackFinishTime : -1;
1760 }
1761
1762 public long getCaptureStartTime() {
1763 return (mCurrentModule instanceof PhotoModule) ?
1764 ((PhotoModule) mCurrentModule).mCaptureStartTime : -1;
1765 }
1766
1767 public boolean isRecording() {
1768 return (mCurrentModule instanceof VideoModule) ?
1769 ((VideoModule) mCurrentModule).isRecording() : false;
1770 }
Angus Kong4f795b82013-09-16 14:25:35 -07001771
Angus Kong62848152013-11-08 17:25:29 -08001772 public CameraManager.CameraOpenCallback getCameraOpenErrorCallback() {
Angus Kong20fad242013-11-11 18:23:46 -08001773 return mCameraController;
Angus Kong4f795b82013-09-16 14:25:35 -07001774 }
Ruben Brunkd217ed02013-10-08 23:31:13 -07001775
1776 // For debugging purposes only.
1777 public CameraModule getCurrentModule() {
1778 return mCurrentModule;
1779 }
Angus Kong20fad242013-11-11 18:23:46 -08001780
1781 private void setupModules() {
1782 // PhotoModule, the default module.
1783 mModuleManager.registerModule(new ModuleManagerImpl.ModuleAgent() {
1784 @Override
1785 public int getModuleId() {
1786 return ModeListView.MODE_PHOTO;
1787 }
1788
1789 @Override
1790 public boolean requestAppForCamera() {
1791 return true;
1792 }
1793
1794 @Override
1795 public ModuleController createModule() {
1796 return new PhotoModule();
1797 }
1798 });
1799 mModuleManager.setDefaultModuleIndex(ModeListView.MODE_PHOTO);
1800
1801 // VideoModule.
1802 mModuleManager.registerModule(new ModuleManagerImpl.ModuleAgent() {
1803 @Override
1804 public int getModuleId() {
1805 return ModeListView.MODE_VIDEO;
1806 }
1807
1808 @Override
1809 public boolean requestAppForCamera() {
1810 return true;
1811 }
1812
1813 @Override
1814 public ModuleController createModule() {
1815 return new VideoModule();
1816 }
1817 });
1818
1819 // WideAngle.
1820 mModuleManager.registerModule(new ModuleManagerImpl.ModuleAgent() {
1821 @Override
1822 public int getModuleId() {
1823 return ModeListView.MODE_WIDEANGLE;
1824 }
1825
1826 @Override
1827 public boolean requestAppForCamera() {
1828 return false;
1829 }
1830
1831 @Override
1832 public ModuleController createModule() {
1833 // TODO: remove the type casting.
1834 return new WideAnglePanoramaModule();
1835 }
1836 });
1837
1838 // PhotoSphere.
1839 if (PhotoSphereHelper.hasLightCycleCapture(this)) {
1840 mModuleManager.registerModule(new ModuleManagerImpl.ModuleAgent() {
1841 @Override
1842 public int getModuleId() {
1843 return ModeListView.MODE_PHOTOSPHERE;
1844 }
1845
1846 @Override
1847 public boolean requestAppForCamera() {
1848 return false;
1849 }
1850
1851 @Override
1852 public ModuleController createModule() {
1853 // TODO: remove the type casting.
1854 return (ModuleController) PhotoSphereHelper.createPanoramaModule();
1855 }
1856 });
1857 }
1858
1859 // Refocus.
1860 if (RefocusHelper.hasRefocusCapture(this)) {
1861 mModuleManager.registerModule(new ModuleManagerImpl.ModuleAgent() {
1862 @Override
1863 public int getModuleId() {
1864 return ModeListView.MODE_CRAFT;
1865 }
1866
1867 @Override
1868 public boolean requestAppForCamera() {
1869 return false;
1870 }
1871
1872 @Override
1873 public ModuleController createModule() {
1874 // TODO: remove the type casting.
1875 return (ModuleController) RefocusHelper.createRefocusModule();
1876 }
1877 });
1878 }
1879
1880 // Gcam for HDR+.
1881 if (GcamHelper.hasGcamCapture()) {
1882 mModuleManager.registerModule(new ModuleManagerImpl.ModuleAgent() {
1883 @Override
1884 public int getModuleId() {
1885 return ModeListView.MODE_GCAM;
1886 }
1887
1888 @Override
1889 public boolean requestAppForCamera() {
1890 return false;
1891 }
1892
1893 @Override
1894 public ModuleController createModule() {
1895 return (ModuleController) GcamHelper.createGcamModule();
1896 }
1897 });
1898 }
1899 }
Michael Kolb8872c232013-01-29 10:33:22 -08001900}