blob: e1f37fe70c813290c08145c09108dfa9c41250ba [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;
Doris Liu6432cd62013-06-13 17:20:31 -070025import android.content.ContentResolver;
Michael Kolb08650182013-02-25 19:43:56 -080026import android.content.Context;
Michael Kolb8872c232013-01-29 10:33:22 -080027import android.content.Intent;
Doris Liub84b9732013-06-18 17:14:26 -070028import android.content.IntentFilter;
Sascha Haeberling2654dd92013-08-28 15:28:57 -070029import android.content.SharedPreferences;
Doris Liu3cf565c2013-02-15 10:55:37 -080030import android.content.pm.ActivityInfo;
Michael Kolb8872c232013-01-29 10:33:22 -080031import android.content.res.Configuration;
Angus Kong9f1db522013-11-09 16:25:59 -080032import android.graphics.Bitmap;
Erin Dahlgrenc120b0f2013-11-19 10:53:49 -080033import android.graphics.Color;
Angus Kong9f1db522013-11-09 16:25:59 -080034import android.graphics.SurfaceTexture;
Doris Liu6432cd62013-06-13 17:20:31 -070035import android.graphics.drawable.ColorDrawable;
36import android.net.Uri;
Mangesh Ghiwarea5682ab2013-09-19 09:24:23 -070037import android.nfc.NfcAdapter;
38import android.nfc.NfcAdapter.CreateBeamUrisCallback;
39import android.nfc.NfcEvent;
Sascha Haeberling6f64b502013-08-14 16:23:18 -070040import android.os.AsyncTask;
Mangesh Ghiwarea5682ab2013-09-19 09:24:23 -070041import android.os.Build;
Michael Kolb8872c232013-01-29 10:33:22 -080042import android.os.Bundle;
Doris Liu6432cd62013-06-13 17:20:31 -070043import android.os.Handler;
Doris Liuaa874422013-09-18 19:43:12 -070044import android.os.Looper;
45import android.os.Message;
Sascha Haeberling2654dd92013-08-28 15:28:57 -070046import android.preference.PreferenceManager;
Doris Liu2a7f44c2013-08-12 15:18:53 -070047import android.provider.MediaStore;
Doris Liu3cf565c2013-02-15 10:55:37 -080048import android.provider.Settings;
Sascha Haeberling37f36112013-08-06 14:31:52 -070049import android.util.Log;
Erin Dahlgrenc120b0f2013-11-19 10:53:49 -080050import android.view.Gravity;
Michael Kolb8872c232013-01-29 10:33:22 -080051import android.view.KeyEvent;
Doris Liu6432cd62013-06-13 17:20:31 -070052import android.view.LayoutInflater;
ztenghui0353ca22013-08-13 13:53:16 -070053import android.view.Menu;
54import android.view.MenuInflater;
55import android.view.MenuItem;
Doris Liu742cd5b2013-09-12 16:17:43 -070056import android.view.MotionEvent;
Michael Kolb8872c232013-01-29 10:33:22 -080057import android.view.View;
Doris Liu6432cd62013-06-13 17:20:31 -070058import android.view.ViewGroup;
Michael Kolb08650182013-02-25 19:43:56 -080059import android.view.Window;
60import android.view.WindowManager;
Angus Kong653c43b2013-08-21 18:28:43 -070061import android.widget.FrameLayout;
Erin Dahlgrenc120b0f2013-11-19 10:53:49 -080062import android.widget.FrameLayout.LayoutParams;
Doris Liu6432cd62013-06-13 17:20:31 -070063import android.widget.ImageView;
Erin Dahlgrenc120b0f2013-11-19 10:53:49 -080064import android.widget.PopupWindow;
Sascha Haeberling37f36112013-08-06 14:31:52 -070065import android.widget.ProgressBar;
Mangesh Ghiwarecd2eeb02013-08-23 13:28:21 -070066import android.widget.ShareActionProvider;
Michael Kolb8872c232013-01-29 10:33:22 -080067
Angus Kong9f1db522013-11-09 16:25:59 -080068import com.android.camera.app.AppController;
Angus Konged15d1a2013-08-19 15:06:12 -070069import com.android.camera.app.AppManagerFactory;
Doris Liuf55f3c42013-11-20 00:24:46 -080070import com.android.camera.app.CameraAppUI;
Angus Kong20fad242013-11-11 18:23:46 -080071import com.android.camera.app.CameraController;
72import com.android.camera.app.CameraManager;
73import com.android.camera.app.CameraManagerFactory;
74import com.android.camera.app.CameraProvider;
Angus Kongc4e66562013-11-22 23:03:21 -080075import com.android.camera.app.CameraServices;
Angus Kong62848152013-11-08 17:25:29 -080076import com.android.camera.app.ImageTaskManager;
Angus Kongfd4fc0e2013-11-07 15:38:09 -080077import com.android.camera.app.MediaSaver;
Angus Kong20fad242013-11-11 18:23:46 -080078import com.android.camera.app.ModuleManagerImpl;
Angus Kong9f1db522013-11-09 16:25:59 -080079import com.android.camera.app.OrientationManager;
80import com.android.camera.app.OrientationManagerImpl;
Angus Konged15d1a2013-08-19 15:06:12 -070081import com.android.camera.app.PanoramaStitchingManager;
Angus Kong20fad242013-11-11 18:23:46 -080082import com.android.camera.app.PlaceholderManager;
nicolasroard19ab7252013-09-18 16:54:05 -070083import com.android.camera.crop.CropActivity;
Doris Liu6432cd62013-06-13 17:20:31 -070084import com.android.camera.data.CameraDataAdapter;
Angus Kong8e5e4ee2013-07-30 11:36:00 -070085import com.android.camera.data.CameraPreviewData;
86import com.android.camera.data.FixedFirstDataAdapter;
87import com.android.camera.data.FixedLastDataAdapter;
Angus Kong32509872013-10-02 16:53:40 -070088import com.android.camera.data.InProgressDataWrapper;
Doris Liu6432cd62013-06-13 17:20:31 -070089import com.android.camera.data.LocalData;
Angus Kong8e5e4ee2013-07-30 11:36:00 -070090import com.android.camera.data.LocalDataAdapter;
ztenghui064d6002013-09-05 15:47:58 -070091import com.android.camera.data.LocalMediaObserver;
Sascha Haeberling6f64b502013-08-14 16:23:18 -070092import com.android.camera.data.MediaDetails;
Angus Kongbd260692013-08-07 14:52:56 -070093import com.android.camera.data.SimpleViewData;
Angus Kong62848152013-11-08 17:25:29 -080094import com.android.camera.filmstrip.FilmstripController;
95import com.android.camera.filmstrip.FilmstripImageData;
96import com.android.camera.filmstrip.FilmstripListener;
Angus Kong612321f2013-11-18 16:17:43 -080097import com.android.camera.module.ModulesInfo;
Erin Dahlgren357b7672013-11-20 17:38:14 -080098import com.android.camera.settings.SettingsManager;
99import com.android.camera.settings.SettingsManager.SettingsCapabilities;
100import com.android.camera.settings.SettingsManager.StartupModuleSetting;
Sascha Haeberlinga5a08d72013-09-11 20:30:52 -0700101import com.android.camera.tinyplanet.TinyPlanetFragment;
Sascha Haeberling280fd3e2013-11-21 13:52:15 -0800102import com.android.camera.ui.CameraControls;
Sascha Haeberling6f64b502013-08-14 16:23:18 -0700103import com.android.camera.ui.DetailsDialog;
Angus Kong62848152013-11-08 17:25:29 -0800104import com.android.camera.ui.FilmstripView;
Doris Liuf55f3c42013-11-20 00:24:46 -0800105import com.android.camera.ui.MainActivityLayout;
Doris Liu1c94b7d2013-11-09 19:13:44 -0800106import com.android.camera.ui.ModeListView;
Erin Dahlgrenc120b0f2013-11-19 10:53:49 -0800107import com.android.camera.ui.SettingsView;
Sascha Haeberling88ef7662013-08-15 17:19:22 -0700108import com.android.camera.util.ApiHelper;
Angus Kongb50b5cb2013-08-09 14:55:20 -0700109import com.android.camera.util.CameraUtil;
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700110import com.android.camera.util.GcamHelper;
Alan Newberger761306f2013-10-30 12:51:21 -0700111import com.android.camera.util.IntentHelper;
Sascha Haeberling88ef7662013-08-15 17:19:22 -0700112import com.android.camera.util.PhotoSphereHelper.PanoramaViewHelper;
Seth Raphaelcbd82672013-11-05 10:12:36 -0800113import com.android.camera.util.UsageStatistics;
Sascha Haeberling8e963a52013-08-06 11:43:02 -0700114import com.android.camera2.R;
Michael Kolb8872c232013-01-29 10:33:22 -0800115
Seth Raphaelcbd82672013-11-05 10:12:36 -0800116import java.io.File;
Erin Dahlgren357b7672013-11-20 17:38:14 -0800117import java.util.List;
Seth Raphaelcbd82672013-11-05 10:12:36 -0800118
Doris Liu6432cd62013-06-13 17:20:31 -0700119public class CameraActivity extends Activity
Doris Liuf55f3c42013-11-20 00:24:46 -0800120 implements AppController, CameraManager.CameraOpenCallback,
Angus Kong9f1db522013-11-09 16:25:59 -0800121 ActionBar.OnMenuVisibilityListener, ShareActionProvider.OnShareTargetSelectedListener,
122 OrientationManager.OnOrientationChangeListener {
Doris Liu6432cd62013-06-13 17:20:31 -0700123
124 private static final String TAG = "CAM_Activity";
125
Doris Liu6432cd62013-06-13 17:20:31 -0700126 private static final String INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE =
127 "android.media.action.STILL_IMAGE_CAMERA_SECURE";
128 public static final String ACTION_IMAGE_CAPTURE_SECURE =
129 "android.media.action.IMAGE_CAPTURE_SECURE";
ztenghui6b920322013-08-16 16:21:22 -0700130 public static final String ACTION_TRIM_VIDEO =
131 "com.android.camera.action.TRIM";
132 public static final String MEDIA_ITEM_PATH = "media-item-path";
Doris Liu6432cd62013-06-13 17:20:31 -0700133
134 // The intent extra for camera from secure lock screen. True if the gallery
135 // should only show newly captured pictures. sSecureAlbumId does not
136 // increment. This is used when switching between camera, camcorder, and
137 // panorama. If the extra is not set, it is in the normal camera mode.
138 public static final String SECURE_CAMERA_EXTRA = "secure_camera";
139
Sascha Haeberlingb7639c62013-09-09 14:42:43 -0700140 /**
Angus Kong20fad242013-11-11 18:23:46 -0800141 * Request code from an activity we started that indicated that we do not want
142 * to reset the view to the preview in onResume.
Sascha Haeberlingb7639c62013-09-09 14:42:43 -0700143 */
144 public static final int REQ_CODE_DONT_SWITCH_TO_PREVIEW = 142;
145
Ruben Brunkd217ed02013-10-08 23:31:13 -0700146 public static final int REQ_CODE_GCAM_DEBUG_POSTCAPTURE = 999;
147
Angus Kong13e87c42013-11-25 10:02:47 -0800148 private static final int MSG_HIDE_ACTION_BAR = 1;
149 private static final int MSG_CLEAR_SCREEN_ON_FLAG = 2;
Doris Liuaa874422013-09-18 19:43:12 -0700150 private static final long SHOW_ACTION_BAR_TIMEOUT_MS = 3000;
Angus Kong13e87c42013-11-25 10:02:47 -0800151 private static final long SCREEN_DELAY_MS = 2 * 60 * 1000; // 2 mins.
Doris Liuaa874422013-09-18 19:43:12 -0700152
Angus Kong20fad242013-11-11 18:23:46 -0800153 /**
154 * Whether onResume should reset the view to the preview.
155 */
Sascha Haeberlingb7639c62013-09-09 14:42:43 -0700156 private boolean mResetToPreviewOnResume = true;
157
ztenghui0353ca22013-08-13 13:53:16 -0700158 // Supported operations at FilmStripView. Different data has different
159 // set of supported operations.
160 private static final int SUPPORT_DELETE = 1 << 0;
161 private static final int SUPPORT_ROTATE = 1 << 1;
162 private static final int SUPPORT_INFO = 1 << 2;
163 private static final int SUPPORT_CROP = 1 << 3;
164 private static final int SUPPORT_SETAS = 1 << 4;
165 private static final int SUPPORT_EDIT = 1 << 5;
166 private static final int SUPPORT_TRIM = 1 << 6;
Mangesh Ghiwarecd2eeb02013-08-23 13:28:21 -0700167 private static final int SUPPORT_SHARE = 1 << 7;
168 private static final int SUPPORT_SHARE_PANORAMA360 = 1 << 8;
169 private static final int SUPPORT_SHOW_ON_MAP = 1 << 9;
ztenghui0353ca22013-08-13 13:53:16 -0700170 private static final int SUPPORT_ALL = 0xffffffff;
171
Angus Kong20fad242013-11-11 18:23:46 -0800172 /**
173 * This data adapter is used by FilmStripView.
174 */
Angus Kong8e5e4ee2013-07-30 11:36:00 -0700175 private LocalDataAdapter mDataAdapter;
Angus Kong20fad242013-11-11 18:23:46 -0800176 /**
177 * This data adapter represents the real local camera data.
178 */
Angus Kong8e5e4ee2013-07-30 11:36:00 -0700179 private LocalDataAdapter mWrappedDataAdapter;
180
Erin Dahlgrenc120b0f2013-11-19 10:53:49 -0800181 private SettingsManager mSettingsManager;
Erin Dahlgren357b7672013-11-20 17:38:14 -0800182 private SettingsController mSettingsController;
Angus Kong6798c342013-07-16 15:14:58 -0700183 private PanoramaStitchingManager mPanoramaManager;
Ruben Brunk7cfcafd2013-10-17 15:41:44 -0700184 private PlaceholderManager mPlaceholderManager;
Doris Liu70576b62013-11-14 20:30:33 -0800185 private ModeListView mModeListView;
Erin Dahlgrenc120b0f2013-11-19 10:53:49 -0800186 private int mCurrentModeIndex;
Doris Liu6432cd62013-06-13 17:20:31 -0700187 private CameraModule mCurrentModule;
Angus Kong20fad242013-11-11 18:23:46 -0800188 private ModuleManagerImpl mModuleManager;
Angus Kong653c43b2013-08-21 18:28:43 -0700189 private FrameLayout mAboveFilmstripControlLayout;
Angus Kong9f1db522013-11-09 16:25:59 -0800190 private FrameLayout mCameraModuleRootView;
Angus Kong62848152013-11-08 17:25:29 -0800191 private FilmstripController mFilmstripController;
Sascha Haeberling37f36112013-08-06 14:31:52 -0700192 private ProgressBar mBottomProgress;
193 private View mPanoStitchingPanel;
Doris Liu6432cd62013-06-13 17:20:31 -0700194 private int mResultCodeForTesting;
195 private Intent mResultDataForTesting;
196 private OnScreenHint mStorageHint;
Angus Kong2dcc0a92013-09-25 13:00:08 -0700197 private long mStorageSpaceBytes = Storage.LOW_STORAGE_THRESHOLD_BYTES;
Doris Liu3cf565c2013-02-15 10:55:37 -0800198 private boolean mAutoRotateScreen;
Doris Liu6432cd62013-06-13 17:20:31 -0700199 private boolean mSecureCamera;
Doris Liu6432cd62013-06-13 17:20:31 -0700200 private int mLastRawOrientation;
Angus Kong9f1db522013-11-09 16:25:59 -0800201 private OrientationManagerImpl mOrientationManager;
Erin Dahlgren21c21a62013-11-19 16:37:38 -0800202 private LocationManager mLocationManager;
Doris Liu6432cd62013-06-13 17:20:31 -0700203 private Handler mMainHandler;
Sascha Haeberlingf1f51862013-07-31 11:28:21 -0700204 private PanoramaViewHelper mPanoramaViewHelper;
Angus Kong8e5e4ee2013-07-30 11:36:00 -0700205 private CameraPreviewData mCameraPreviewData;
ztenghuifa9e2cc2013-08-09 17:37:15 -0700206 private ActionBar mActionBar;
Doris Liuaa874422013-09-18 19:43:12 -0700207 private OnActionBarVisibilityListener mOnActionBarVisibilityListener = null;
ztenghui0353ca22013-08-13 13:53:16 -0700208 private Menu mActionBarMenu;
Angus Kong653c43b2013-08-21 18:28:43 -0700209 private ViewGroup mUndoDeletionBar;
Doris Liu742cd5b2013-09-12 16:17:43 -0700210 private boolean mIsUndoingDeletion = false;
Doris Liu3cf565c2013-02-15 10:55:37 -0800211
Sascha Haeberling280fd3e2013-11-21 13:52:15 -0800212 private final Uri[] mNfcPushUris = new Uri[1];
Mangesh Ghiwarea5682ab2013-09-19 09:24:23 -0700213
Mangesh Ghiwarecd2eeb02013-08-23 13:28:21 -0700214 private ShareActionProvider mStandardShareActionProvider;
215 private Intent mStandardShareIntent;
216 private ShareActionProvider mPanoramaShareActionProvider;
217 private Intent mPanoramaShareIntent;
ztenghui064d6002013-09-05 15:47:58 -0700218 private LocalMediaObserver mLocalImagesObserver;
219 private LocalMediaObserver mLocalVideosObserver;
Mangesh Ghiwarecd2eeb02013-08-23 13:28:21 -0700220
Sascha Haeberling5199c202013-09-05 17:10:19 -0700221 private final int DEFAULT_SYSTEM_UI_VISIBILITY = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
222 | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
Doris Liu742cd5b2013-09-12 16:17:43 -0700223 private boolean mPendingDeletion = false;
Sascha Haeberling5199c202013-09-05 17:10:19 -0700224
ztenghui05804752013-09-17 11:33:02 -0700225 private Intent mVideoShareIntent;
226 private Intent mImageShareIntent;
227
Angus Kong20fad242013-11-11 18:23:46 -0800228 private CameraController mCameraController;
Erin Dahlgrenc120b0f2013-11-19 10:53:49 -0800229 private boolean mPaused;
Doris Liuf55f3c42013-11-20 00:24:46 -0800230 private CameraAppUI mCameraAppUI;
Angus Kong20fad242013-11-11 18:23:46 -0800231
Angus Kongfd4fc0e2013-11-07 15:38:09 -0800232 private MediaSaver mMediaSaver;
Doris Liu6432cd62013-06-13 17:20:31 -0700233
Doris Liub84b9732013-06-18 17:14:26 -0700234 // close activity when screen turns off
Sascha Haeberling280fd3e2013-11-21 13:52:15 -0800235 private final BroadcastReceiver mScreenOffReceiver = new BroadcastReceiver() {
Doris Liub84b9732013-06-18 17:14:26 -0700236 @Override
237 public void onReceive(Context context, Intent intent) {
238 finish();
239 }
240 };
241
Angus Kong6a8e8a12013-07-19 14:55:07 -0700242 private static BroadcastReceiver sScreenOffReceiver;
Sascha Haeberlinga5a08d72013-09-11 20:30:52 -0700243
Angus Kong13e87c42013-11-25 10:02:47 -0800244 /**
245 * Whether the screen is kept turned on.
246 */
247 private boolean mKeepScreenOn;
248
Angus Kong20fad242013-11-11 18:23:46 -0800249 @Override
250 public void onCameraOpened(CameraManager.CameraProxy camera) {
Erin Dahlgrenc120b0f2013-11-19 10:53:49 -0800251 if (!mModuleManager.getModuleAgent(mCurrentModeIndex).requestAppForCamera()) {
Angus Kong20fad242013-11-11 18:23:46 -0800252 // We shouldn't be here. Just close the camera and leave.
253 camera.release(false);
254 throw new IllegalStateException("Camera opened but the module shouldn't be " +
255 "requesting");
256 }
Angus Kong13e87c42013-11-25 10:02:47 -0800257 if (mCurrentModule != null) {
Erin Dahlgren357b7672013-11-20 17:38:14 -0800258 SettingsCapabilities capabilities =
259 SettingsController.getSettingsCapabilities(camera);
260 mSettingsManager.changeCamera(camera.getCameraId(), capabilities);
Angus Kong13e87c42013-11-25 10:02:47 -0800261 mCurrentModule.onCameraAvailable(camera);
Angus Kong20fad242013-11-11 18:23:46 -0800262 }
263 }
264
265 @Override
266 public void onCameraDisabled(int cameraId) {
267 UsageStatistics.onEvent(UsageStatistics.COMPONENT_CAMERA, UsageStatistics.ACTION_OPEN_FAIL,
268 "security");
269
270 CameraUtil.showErrorAndFinish(this, R.string.camera_disabled);
271 }
272
273 @Override
274 public void onDeviceOpenFailure(int cameraId) {
275 UsageStatistics.onEvent(UsageStatistics.COMPONENT_CAMERA,
276 UsageStatistics.ACTION_OPEN_FAIL, "open");
277
278 CameraUtil.showErrorAndFinish(this, R.string.cannot_connect_camera);
279 }
280
281 @Override
282 public void onReconnectionFailure(CameraManager mgr) {
283 UsageStatistics.onEvent(UsageStatistics.COMPONENT_CAMERA,
284 UsageStatistics.ACTION_OPEN_FAIL, "reconnect");
285
286 CameraUtil.showErrorAndFinish(this, R.string.cannot_connect_camera);
287 }
288
Doris Liuaa874422013-09-18 19:43:12 -0700289 private class MainHandler extends Handler {
290 public MainHandler(Looper looper) {
291 super(looper);
292 }
293
294 @Override
295 public void handleMessage(Message msg) {
Angus Kong13e87c42013-11-25 10:02:47 -0800296 switch (msg.what) {
297 case MSG_HIDE_ACTION_BAR: {
298 removeMessages(MSG_HIDE_ACTION_BAR);
299 CameraActivity.this.setSystemBarsVisibility(false);
300 break;
301 }
302
303 case MSG_CLEAR_SCREEN_ON_FLAG: {
304 if (!mPaused) {
305 getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
306 }
307 break;
308 }
309
310 default:
Doris Liuaa874422013-09-18 19:43:12 -0700311 }
312 }
313 }
314
315 public interface OnActionBarVisibilityListener {
316 public void onActionBarVisibilityChanged(boolean isVisible);
317 }
318
319 public void setOnActionBarVisibilityListener(OnActionBarVisibilityListener listener) {
320 mOnActionBarVisibilityListener = listener;
321 }
322
Seth Raphaelcbd82672013-11-05 10:12:36 -0800323 private String fileNameFromDataID(int dataID) {
324 final LocalData localData = mDataAdapter.getLocalData(dataID);
325
326 File localFile = new File(localData.getPath());
327 return localFile.getName();
328 }
329
Sascha Haeberling280fd3e2013-11-21 13:52:15 -0800330 private final FilmstripListener mFilmStripListener =
Angus Kong62848152013-11-08 17:25:29 -0800331 new FilmstripListener() {
Sascha Haeberling37f36112013-08-06 14:31:52 -0700332 @Override
333 public void onDataPromoted(int dataID) {
Seth Raphaelcbd82672013-11-05 10:12:36 -0800334 UsageStatistics.onEvent(UsageStatistics.COMPONENT_CAMERA,
335 UsageStatistics.ACTION_DELETE, "promoted", 0,
336 UsageStatistics.hashFileName(fileNameFromDataID(dataID)));
337
Sascha Haeberling37f36112013-08-06 14:31:52 -0700338 removeData(dataID);
339 }
Doris Liu6432cd62013-06-13 17:20:31 -0700340
Sascha Haeberling37f36112013-08-06 14:31:52 -0700341 @Override
342 public void onDataDemoted(int dataID) {
Seth Raphaelcbd82672013-11-05 10:12:36 -0800343 UsageStatistics.onEvent(UsageStatistics.COMPONENT_CAMERA,
344 UsageStatistics.ACTION_DELETE, "demoted", 0,
345 UsageStatistics.hashFileName(fileNameFromDataID(dataID)));
346
Sascha Haeberling37f36112013-08-06 14:31:52 -0700347 removeData(dataID);
348 }
Doris Liu6432cd62013-06-13 17:20:31 -0700349
Sascha Haeberling37f36112013-08-06 14:31:52 -0700350 @Override
351 public void onDataFullScreenChange(int dataID, boolean full) {
ztenghui8566dd72013-09-12 14:56:56 -0700352 boolean isCameraID = isCameraPreview(dataID);
ztenghui7b265a62013-09-09 14:58:44 -0700353 if (!isCameraID) {
Doris Liuaa874422013-09-18 19:43:12 -0700354 if (!full) {
355 // Always show action bar in filmstrip mode
356 CameraActivity.this.setSystemBarsVisibility(true, false);
357 } else if (mActionBar.isShowing()) {
358 // Hide action bar after time out in full screen mode
Angus Kong13e87c42013-11-25 10:02:47 -0800359 mMainHandler.sendEmptyMessageDelayed(MSG_HIDE_ACTION_BAR,
Doris Liuaa874422013-09-18 19:43:12 -0700360 SHOW_ACTION_BAR_TIMEOUT_MS);
361 }
ztenghuifa9e2cc2013-08-09 17:37:15 -0700362 }
Sascha Haeberling37f36112013-08-06 14:31:52 -0700363 }
364
ztenghui8566dd72013-09-12 14:56:56 -0700365 /**
366 * Check if the local data corresponding to dataID is the camera
367 * preview.
368 *
369 * @param dataID the ID of the local data
370 * @return true if the local data is not null and it is the
371 * camera preview.
372 */
373 private boolean isCameraPreview(int dataID) {
374 LocalData localData = mDataAdapter.getLocalData(dataID);
375 if (localData == null) {
376 Log.w(TAG, "Current data ID not found.");
377 return false;
378 }
379 return localData.getLocalDataType() == LocalData.LOCAL_CAMERA_PREVIEW;
380 }
381
Sascha Haeberling37f36112013-08-06 14:31:52 -0700382 @Override
Angus Kongc02b13a2013-11-12 11:50:57 -0800383 public void onDataReloaded() {
Erin Dahlgren3044d8c2013-10-10 18:23:45 -0700384 setPreviewControlsVisibility(true);
ztenghui17f1e652013-11-06 14:20:31 -0800385 CameraActivity.this.setSystemBarsVisibility(false);
Erin Dahlgren3044d8c2013-10-10 18:23:45 -0700386 }
387
388 @Override
389 public void onCurrentDataCentered(int dataID) {
Angus Kong62848152013-11-08 17:25:29 -0800390 if (dataID != 0 && !mFilmstripController.isCameraPreview()) {
Erin Dahlgren3044d8c2013-10-10 18:23:45 -0700391 // For now, We ignore all items that are not the camera preview.
392 return;
393 }
394
Angus Kong20fad242013-11-11 18:23:46 -0800395 if (!arePreviewControlsVisible()) {
Erin Dahlgren3044d8c2013-10-10 18:23:45 -0700396 setPreviewControlsVisibility(true);
Erin Dahlgrenfd7f0a92013-10-21 10:08:54 -0700397 CameraActivity.this.setSystemBarsVisibility(false);
Erin Dahlgren3044d8c2013-10-10 18:23:45 -0700398 }
399 }
400
401 @Override
402 public void onCurrentDataOffCentered(int dataID) {
Angus Kong62848152013-11-08 17:25:29 -0800403 if (dataID != 0 && !mFilmstripController.isCameraPreview()) {
Erin Dahlgren3044d8c2013-10-10 18:23:45 -0700404 // For now, We ignore all items that are not the camera preview.
405 return;
406 }
407
408 if (arePreviewControlsVisible()) {
409 setPreviewControlsVisibility(false);
410 }
411 }
412
413 @Override
Angus Kong02cafdf2013-10-13 19:26:02 -0700414 public void onDataFocusChanged(final int dataID, final boolean focused) {
Doris Liuaa874422013-09-18 19:43:12 -0700415 // Delay hiding action bar if there is any user interaction
Angus Kong13e87c42013-11-25 10:02:47 -0800416 if (mMainHandler.hasMessages(MSG_HIDE_ACTION_BAR)) {
417 mMainHandler.removeMessages(MSG_HIDE_ACTION_BAR);
418 mMainHandler.sendEmptyMessageDelayed(MSG_HIDE_ACTION_BAR,
Doris Liuaa874422013-09-18 19:43:12 -0700419 SHOW_ACTION_BAR_TIMEOUT_MS);
420 }
Angus Kong02cafdf2013-10-13 19:26:02 -0700421 // TODO: This callback is UI event callback, should always
422 // happen on UI thread. Find the reason for this
423 // runOnUiThread() and fix it.
Mangesh Ghiware33035c12013-08-23 13:28:21 -0700424 runOnUiThread(new Runnable() {
425 @Override
426 public void run() {
ztenghui7b265a62013-09-09 14:58:44 -0700427 LocalData currentData = mDataAdapter.getLocalData(dataID);
428 if (currentData == null) {
429 Log.w(TAG, "Current data ID not found.");
430 hidePanoStitchingProgress();
431 return;
432 }
433 boolean isCameraID = currentData.getLocalDataType() ==
434 LocalData.LOCAL_CAMERA_PREVIEW;
Angus Kong02cafdf2013-10-13 19:26:02 -0700435 if (!focused) {
ztenghui7b265a62013-09-09 14:58:44 -0700436 if (isCameraID) {
437 mCurrentModule.onPreviewFocusChanged(false);
Doris Liuaa874422013-09-18 19:43:12 -0700438 CameraActivity.this.setSystemBarsVisibility(true);
ztenghui7b265a62013-09-09 14:58:44 -0700439 }
Mangesh Ghiware33035c12013-08-23 13:28:21 -0700440 hidePanoStitchingProgress();
441 } else {
ztenghui7b265a62013-09-09 14:58:44 -0700442 if (isCameraID) {
Sascha Haeberlinga5a08d72013-09-11 20:30:52 -0700443 // Don't show the action bar in Camera
444 // preview.
Doris Liuaa874422013-09-18 19:43:12 -0700445 CameraActivity.this.setSystemBarsVisibility(false);
Erin Dahlgren3044d8c2013-10-10 18:23:45 -0700446
Doris Liu742cd5b2013-09-12 16:17:43 -0700447 if (mPendingDeletion) {
448 performDeletion();
449 }
Alan Newberger1ef76d42013-09-04 19:01:59 -0700450 } else {
451 updateActionBarMenu(dataID);
452 }
ztenghui2c3d9a52013-09-03 11:27:21 -0700453
Mangesh Ghiware33035c12013-08-23 13:28:21 -0700454 Uri contentUri = currentData.getContentUri();
455 if (contentUri == null) {
456 hidePanoStitchingProgress();
457 return;
458 }
Angus Kong20fad242013-11-11 18:23:46 -0800459 int panoStitchingProgress = mPanoramaManager.getTaskProgress(contentUri);
Mangesh Ghiware33035c12013-08-23 13:28:21 -0700460 if (panoStitchingProgress < 0) {
461 hidePanoStitchingProgress();
462 return;
463 }
464 showPanoStitchingProgress();
465 updateStitchingProgress(panoStitchingProgress);
466 }
ztenghui2c3d9a52013-09-03 11:27:21 -0700467 }
Mangesh Ghiware33035c12013-08-23 13:28:21 -0700468 });
Sascha Haeberling37f36112013-08-06 14:31:52 -0700469 }
Sascha Haeberling394023f2013-08-15 15:57:29 -0700470
471 @Override
Doris Liuaa874422013-09-18 19:43:12 -0700472 public void onToggleSystemDecorsVisibility(int dataID) {
473 // If action bar is showing, hide it immediately, otherwise
474 // show action bar and hide it later
Sascha Haeberling394023f2013-08-15 15:57:29 -0700475 if (mActionBar.isShowing()) {
Doris Liuaa874422013-09-18 19:43:12 -0700476 CameraActivity.this.setSystemBarsVisibility(false);
Sascha Haeberling394023f2013-08-15 15:57:29 -0700477 } else {
ztenghui8566dd72013-09-12 14:56:56 -0700478 // Don't show the action bar if that is the camera preview.
479 boolean isCameraID = isCameraPreview(dataID);
480 if (!isCameraID) {
Doris Liuaa874422013-09-18 19:43:12 -0700481 CameraActivity.this.setSystemBarsVisibility(true, true);
ztenghuifd43e3b2013-09-03 11:30:11 -0700482 }
Sascha Haeberling394023f2013-08-15 15:57:29 -0700483 }
484 }
Doris Liuaa874422013-09-18 19:43:12 -0700485
486 @Override
487 public void setSystemDecorsVisibility(boolean visible) {
488 CameraActivity.this.setSystemBarsVisibility(visible);
489 }
Sascha Haeberling37f36112013-08-06 14:31:52 -0700490 };
491
Sascha Haeberling4ed20592013-09-13 11:58:33 -0700492 public void gotoGallery() {
Seth Raphaelcbd82672013-11-05 10:12:36 -0800493 UsageStatistics.onEvent(UsageStatistics.COMPONENT_CAMERA, UsageStatistics.ACTION_FILMSTRIP,
494 "thumbnailTap");
495
Angus Kong62848152013-11-08 17:25:29 -0800496 mFilmstripController.goToNextItem();
Sascha Haeberling4ed20592013-09-13 11:58:33 -0700497 }
498
Sascha Haeberling5199c202013-09-05 17:10:19 -0700499 /**
Doris Liuaa874422013-09-18 19:43:12 -0700500 * If {@param visible} is false, this hides the action bar and switches the system UI
501 * to lights-out mode.
Sascha Haeberling5199c202013-09-05 17:10:19 -0700502 */
Doris Liu97cb1ea2013-10-11 16:54:51 -0700503 // TODO: This should not be called outside of the activity.
Sascha Haeberling4ec139d2013-10-09 23:46:20 -0700504 public void setSystemBarsVisibility(boolean visible) {
Doris Liuaa874422013-09-18 19:43:12 -0700505 setSystemBarsVisibility(visible, false);
506 }
507
508 /**
509 * If {@param visible} is false, this hides the action bar and switches the
510 * system UI to lights-out mode. If {@param hideLater} is true, a delayed message
511 * will be sent after a timeout to hide the action bar.
512 */
513 private void setSystemBarsVisibility(boolean visible, boolean hideLater) {
Angus Kong13e87c42013-11-25 10:02:47 -0800514 mMainHandler.removeMessages(MSG_HIDE_ACTION_BAR);
Doris Liuaa874422013-09-18 19:43:12 -0700515
ztenghui17f1e652013-11-06 14:20:31 -0800516 int currentSystemUIVisibility = mAboveFilmstripControlLayout.getSystemUiVisibility();
517 int newSystemUIVisibility = DEFAULT_SYSTEM_UI_VISIBILITY |
518 (visible ? View.SYSTEM_UI_FLAG_VISIBLE :
519 View.SYSTEM_UI_FLAG_LOW_PROFILE | View.SYSTEM_UI_FLAG_FULLSCREEN);
520 if (newSystemUIVisibility != currentSystemUIVisibility) {
521 mAboveFilmstripControlLayout.setSystemUiVisibility(newSystemUIVisibility);
522 }
Doris Liu97cb1ea2013-10-11 16:54:51 -0700523
ztenghui17f1e652013-11-06 14:20:31 -0800524 boolean currentActionBarVisibility = mActionBar.isShowing();
525 if (visible != currentActionBarVisibility) {
Doris Liuaa874422013-09-18 19:43:12 -0700526 if (visible) {
527 mActionBar.show();
528 } else {
529 mActionBar.hide();
530 }
531 if (mOnActionBarVisibilityListener != null) {
532 mOnActionBarVisibilityListener.onActionBarVisibilityChanged(visible);
533 }
534 }
535
536 // Now delay hiding the bars
537 if (visible && hideLater) {
Angus Kong13e87c42013-11-25 10:02:47 -0800538 mMainHandler.sendEmptyMessageDelayed(MSG_HIDE_ACTION_BAR, SHOW_ACTION_BAR_TIMEOUT_MS);
Sascha Haeberling5199c202013-09-05 17:10:19 -0700539 }
Sascha Haeberling5199c202013-09-05 17:10:19 -0700540 }
541
Sascha Haeberling37f36112013-08-06 14:31:52 -0700542 private void hidePanoStitchingProgress() {
543 mPanoStitchingPanel.setVisibility(View.GONE);
544 }
545
546 private void showPanoStitchingProgress() {
547 mPanoStitchingPanel.setVisibility(View.VISIBLE);
548 }
549
550 private void updateStitchingProgress(int progress) {
551 mBottomProgress.setProgress(progress);
552 }
Doris Liu6432cd62013-06-13 17:20:31 -0700553
Mangesh Ghiwarea5682ab2013-09-19 09:24:23 -0700554 @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
555 private void setupNfcBeamPush() {
556 NfcAdapter adapter = NfcAdapter.getDefaultAdapter(CameraActivity.this);
557 if (adapter == null) {
558 return;
559 }
560
561 if (!ApiHelper.HAS_SET_BEAM_PUSH_URIS) {
562 // Disable beaming
563 adapter.setNdefPushMessage(null, CameraActivity.this);
564 return;
565 }
566
567 adapter.setBeamPushUris(null, CameraActivity.this);
568 adapter.setBeamPushUrisCallback(new CreateBeamUrisCallback() {
569 @Override
570 public Uri[] createBeamUris(NfcEvent event) {
571 return mNfcPushUris;
572 }
573 }, CameraActivity.this);
574 }
575
576 private void setNfcBeamPushUri(Uri uri) {
577 mNfcPushUris[0] = uri;
578 }
579
Mangesh Ghiwarecd2eeb02013-08-23 13:28:21 -0700580 private void setStandardShareIntent(Uri contentUri, String mimeType) {
ztenghui05804752013-09-17 11:33:02 -0700581 mStandardShareIntent = getShareIntentFromType(mimeType);
582 if (mStandardShareIntent != null) {
583 mStandardShareIntent.putExtra(Intent.EXTRA_STREAM, contentUri);
584 mStandardShareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
585 if (mStandardShareActionProvider != null) {
586 mStandardShareActionProvider.setShareIntent(mStandardShareIntent);
587 }
Mangesh Ghiwarecd2eeb02013-08-23 13:28:21 -0700588 }
ztenghui05804752013-09-17 11:33:02 -0700589 }
590
591 /**
592 * Get the share intent according to the mimeType
593 *
594 * @param mimeType The mimeType of current data.
595 * @return the video/image's ShareIntent or null if mimeType is invalid.
596 */
597 private Intent getShareIntentFromType(String mimeType) {
598 // Lazily create the intent object.
599 if (mimeType.startsWith("video/")) {
600 if (mVideoShareIntent == null) {
601 mVideoShareIntent = new Intent(Intent.ACTION_SEND);
602 mVideoShareIntent.setType("video/*");
603 }
604 return mVideoShareIntent;
605 } else if (mimeType.startsWith("image/")) {
606 if (mImageShareIntent == null) {
607 mImageShareIntent = new Intent(Intent.ACTION_SEND);
608 mImageShareIntent.setType("image/*");
609 }
610 return mImageShareIntent;
Mangesh Ghiwarecd2eeb02013-08-23 13:28:21 -0700611 }
ztenghui05804752013-09-17 11:33:02 -0700612 Log.w(TAG, "unsupported mimeType " + mimeType);
613 return null;
Mangesh Ghiwarecd2eeb02013-08-23 13:28:21 -0700614 }
615
616 private void setPanoramaShareIntent(Uri contentUri) {
617 if (mPanoramaShareIntent == null) {
618 mPanoramaShareIntent = new Intent(Intent.ACTION_SEND);
619 }
620 mPanoramaShareIntent.setType("application/vnd.google.panorama360+jpg");
621 mPanoramaShareIntent.putExtra(Intent.EXTRA_STREAM, contentUri);
622 if (mPanoramaShareActionProvider != null) {
623 mPanoramaShareActionProvider.setShareIntent(mPanoramaShareIntent);
624 }
625 }
626
Doris Liuaa874422013-09-18 19:43:12 -0700627 @Override
628 public void onMenuVisibilityChanged(boolean isVisible) {
629 // If menu is showing, we need to make sure action bar does not go away.
Angus Kong13e87c42013-11-25 10:02:47 -0800630 mMainHandler.removeMessages(MSG_HIDE_ACTION_BAR);
Doris Liuaa874422013-09-18 19:43:12 -0700631 if (!isVisible) {
Angus Kong13e87c42013-11-25 10:02:47 -0800632 mMainHandler.sendEmptyMessageDelayed(MSG_HIDE_ACTION_BAR, SHOW_ACTION_BAR_TIMEOUT_MS);
Doris Liuaa874422013-09-18 19:43:12 -0700633 }
634 }
635
Seth Raphaelcbd82672013-11-05 10:12:36 -0800636 @Override
637 public boolean onShareTargetSelected(ShareActionProvider shareActionProvider, Intent intent) {
Angus Kong62848152013-11-08 17:25:29 -0800638 int currentDataId = mFilmstripController.getCurrentId();
Seth Raphaelcbd82672013-11-05 10:12:36 -0800639 if (currentDataId < 0) {
640 return false;
641 }
642 UsageStatistics.onEvent(UsageStatistics.COMPONENT_CAMERA, UsageStatistics.ACTION_SHARE,
643 intent.getComponent().getPackageName(), 0,
644 UsageStatistics.hashFileName(fileNameFromDataID(currentDataId)));
645 return true;
646 }
647
ztenghui0353ca22013-08-13 13:53:16 -0700648 /**
649 * According to the data type, make the menu items for supported operations
650 * visible.
Sascha Haeberlinga5a08d72013-09-11 20:30:52 -0700651 *
Sascha Haeberlingfae11a12013-08-15 14:29:49 -0700652 * @param dataID the data ID of the current item.
ztenghui0353ca22013-08-13 13:53:16 -0700653 */
Sascha Haeberlingfae11a12013-08-15 14:29:49 -0700654 private void updateActionBarMenu(int dataID) {
655 LocalData currentData = mDataAdapter.getLocalData(dataID);
Erin Dahlgrend4f69ed2013-10-01 13:42:51 -0700656 if (currentData == null) {
657 return;
658 }
Sascha Haeberlingfae11a12013-08-15 14:29:49 -0700659 int type = currentData.getLocalDataType();
660
ztenghui0353ca22013-08-13 13:53:16 -0700661 if (mActionBarMenu == null) {
662 return;
663 }
664
665 int supported = 0;
Angus Kong32509872013-10-02 16:53:40 -0700666
ztenghui0353ca22013-08-13 13:53:16 -0700667 switch (type) {
668 case LocalData.LOCAL_IMAGE:
669 supported |= SUPPORT_DELETE | SUPPORT_ROTATE | SUPPORT_INFO
670 | SUPPORT_CROP | SUPPORT_SETAS | SUPPORT_EDIT
Mangesh Ghiwarecd2eeb02013-08-23 13:28:21 -0700671 | SUPPORT_SHARE | SUPPORT_SHOW_ON_MAP;
ztenghui0353ca22013-08-13 13:53:16 -0700672 break;
673 case LocalData.LOCAL_VIDEO:
Mangesh Ghiwarecd2eeb02013-08-23 13:28:21 -0700674 supported |= SUPPORT_DELETE | SUPPORT_INFO | SUPPORT_TRIM
675 | SUPPORT_SHARE;
ztenghui0353ca22013-08-13 13:53:16 -0700676 break;
677 case LocalData.LOCAL_PHOTO_SPHERE:
678 supported |= SUPPORT_DELETE | SUPPORT_ROTATE | SUPPORT_INFO
679 | SUPPORT_CROP | SUPPORT_SETAS | SUPPORT_EDIT
Mangesh Ghiwarecd2eeb02013-08-23 13:28:21 -0700680 | SUPPORT_SHARE | SUPPORT_SHOW_ON_MAP;
681 break;
682 case LocalData.LOCAL_360_PHOTO_SPHERE:
683 supported |= SUPPORT_DELETE | SUPPORT_ROTATE | SUPPORT_INFO
684 | SUPPORT_CROP | SUPPORT_SETAS | SUPPORT_EDIT
685 | SUPPORT_SHARE | SUPPORT_SHARE_PANORAMA360
ztenghui0353ca22013-08-13 13:53:16 -0700686 | SUPPORT_SHOW_ON_MAP;
687 break;
688 default:
689 break;
690 }
691
ztenghuie941cbe2013-10-02 17:31:47 -0700692 // In secure camera mode, we only support delete operation.
693 if (isSecureCamera()) {
694 supported &= SUPPORT_DELETE;
695 }
696
ztenghui0353ca22013-08-13 13:53:16 -0700697 setMenuItemVisible(mActionBarMenu, R.id.action_delete,
698 (supported & SUPPORT_DELETE) != 0);
699 setMenuItemVisible(mActionBarMenu, R.id.action_rotate_ccw,
700 (supported & SUPPORT_ROTATE) != 0);
701 setMenuItemVisible(mActionBarMenu, R.id.action_rotate_cw,
702 (supported & SUPPORT_ROTATE) != 0);
Mangesh Ghiwarecd2eeb02013-08-23 13:28:21 -0700703 setMenuItemVisible(mActionBarMenu, R.id.action_details,
704 (supported & SUPPORT_INFO) != 0);
ztenghui0353ca22013-08-13 13:53:16 -0700705 setMenuItemVisible(mActionBarMenu, R.id.action_crop,
706 (supported & SUPPORT_CROP) != 0);
ztenghui0353ca22013-08-13 13:53:16 -0700707 setMenuItemVisible(mActionBarMenu, R.id.action_setas,
708 (supported & SUPPORT_SETAS) != 0);
ztenghui0353ca22013-08-13 13:53:16 -0700709 setMenuItemVisible(mActionBarMenu, R.id.action_edit,
710 (supported & SUPPORT_EDIT) != 0);
Mangesh Ghiwarecd2eeb02013-08-23 13:28:21 -0700711 setMenuItemVisible(mActionBarMenu, R.id.action_trim,
712 (supported & SUPPORT_TRIM) != 0);
713
Mangesh Ghiware33035c12013-08-23 13:28:21 -0700714 boolean standardShare = (supported & SUPPORT_SHARE) != 0;
715 boolean panoramaShare = (supported & SUPPORT_SHARE_PANORAMA360) != 0;
716 setMenuItemVisible(mActionBarMenu, R.id.action_share, standardShare);
717 setMenuItemVisible(mActionBarMenu, R.id.action_share_panorama, panoramaShare);
718
719 if (panoramaShare) {
720 // For 360 PhotoSphere, relegate standard share to the overflow menu
721 MenuItem item = mActionBarMenu.findItem(R.id.action_share);
722 if (item != null) {
723 item.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
724 item.setTitle(getResources().getString(R.string.share_as_photo));
725 }
726 // And, promote "share as panorama" to action bar
727 item = mActionBarMenu.findItem(R.id.action_share_panorama);
728 if (item != null) {
729 item.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
730 }
Mangesh Ghiwarecd2eeb02013-08-23 13:28:21 -0700731 setPanoramaShareIntent(currentData.getContentUri());
732 }
Mangesh Ghiware33035c12013-08-23 13:28:21 -0700733 if (standardShare) {
734 if (!panoramaShare) {
735 MenuItem item = mActionBarMenu.findItem(R.id.action_share);
736 if (item != null) {
737 item.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
738 item.setTitle(getResources().getString(R.string.share));
739 }
740 }
741 setStandardShareIntent(currentData.getContentUri(), currentData.getMimeType());
Mangesh Ghiwarea5682ab2013-09-19 09:24:23 -0700742 setNfcBeamPushUri(currentData.getContentUri());
Mangesh Ghiware33035c12013-08-23 13:28:21 -0700743 }
Sascha Haeberlingfae11a12013-08-15 14:29:49 -0700744
745 boolean itemHasLocation = currentData.getLatLong() != null;
746 setMenuItemVisible(mActionBarMenu, R.id.action_show_on_map,
747 itemHasLocation && (supported & SUPPORT_SHOW_ON_MAP) != 0);
ztenghui0353ca22013-08-13 13:53:16 -0700748 }
749
750 private void setMenuItemVisible(Menu menu, int itemId, boolean visible) {
751 MenuItem item = menu.findItem(itemId);
Angus Kong20fad242013-11-11 18:23:46 -0800752 if (item != null) {
ztenghui0353ca22013-08-13 13:53:16 -0700753 item.setVisible(visible);
Angus Kong20fad242013-11-11 18:23:46 -0800754 }
ztenghui0353ca22013-08-13 13:53:16 -0700755 }
756
Sascha Haeberling280fd3e2013-11-21 13:52:15 -0800757 private final ImageTaskManager.TaskListener mPlaceholderListener =
Ruben Brunk7cfcafd2013-10-17 15:41:44 -0700758 new ImageTaskManager.TaskListener() {
759
760 @Override
761 public void onTaskQueued(String filePath, final Uri imageUri) {
762 mMainHandler.post(new Runnable() {
763 @Override
764 public void run() {
765 notifyNewMedia(imageUri);
766 int dataID = mDataAdapter.findDataByContentUri(imageUri);
767 if (dataID != -1) {
768 LocalData d = mDataAdapter.getLocalData(dataID);
769 InProgressDataWrapper newData = new InProgressDataWrapper(d, true);
770 mDataAdapter.updateData(dataID, newData);
771 }
772 }
773 });
774 }
775
776 @Override
777 public void onTaskDone(String filePath, final Uri imageUri) {
778 mMainHandler.post(new Runnable() {
779 @Override
780 public void run() {
781 mDataAdapter.refresh(getContentResolver(), imageUri);
782 }
783 });
784 }
785
786 @Override
787 public void onTaskProgress(String filePath, Uri imageUri, int progress) {
788 // Do nothing
789 }
Angus Kong20fad242013-11-11 18:23:46 -0800790 };
Ruben Brunk7cfcafd2013-10-17 15:41:44 -0700791
Sascha Haeberling280fd3e2013-11-21 13:52:15 -0800792 private final ImageTaskManager.TaskListener mStitchingListener =
Angus Kong6798c342013-07-16 15:14:58 -0700793 new ImageTaskManager.TaskListener() {
794 @Override
Sascha Haeberling37f36112013-08-06 14:31:52 -0700795 public void onTaskQueued(String filePath, final Uri imageUri) {
796 mMainHandler.post(new Runnable() {
797 @Override
798 public void run() {
799 notifyNewMedia(imageUri);
Angus Kong32509872013-10-02 16:53:40 -0700800 int dataID = mDataAdapter.findDataByContentUri(imageUri);
801 if (dataID != -1) {
802 // Don't allow special UI actions (swipe to
803 // delete, for example) on in-progress data.
804 LocalData d = mDataAdapter.getLocalData(dataID);
805 InProgressDataWrapper newData = new InProgressDataWrapper(d);
806 mDataAdapter.updateData(dataID, newData);
807 }
Sascha Haeberling37f36112013-08-06 14:31:52 -0700808 }
809 });
Angus Kong6798c342013-07-16 15:14:58 -0700810 }
811
812 @Override
Sascha Haeberling37f36112013-08-06 14:31:52 -0700813 public void onTaskDone(String filePath, final Uri imageUri) {
814 Log.v(TAG, "onTaskDone:" + filePath);
815 mMainHandler.post(new Runnable() {
816 @Override
817 public void run() {
818 int doneID = mDataAdapter.findDataByContentUri(imageUri);
Angus Kong62848152013-11-08 17:25:29 -0800819 int currentDataId = mFilmstripController.getCurrentId();
Sascha Haeberling37f36112013-08-06 14:31:52 -0700820
821 if (currentDataId == doneID) {
822 hidePanoStitchingProgress();
823 updateStitchingProgress(0);
824 }
825
826 mDataAdapter.refresh(getContentResolver(), imageUri);
827 }
828 });
Angus Kong6798c342013-07-16 15:14:58 -0700829 }
830
831 @Override
832 public void onTaskProgress(
Sascha Haeberling37f36112013-08-06 14:31:52 -0700833 String filePath, final Uri imageUri, final int progress) {
834 mMainHandler.post(new Runnable() {
835 @Override
836 public void run() {
Angus Kong62848152013-11-08 17:25:29 -0800837 int currentDataId = mFilmstripController.getCurrentId();
Sascha Haeberling37f36112013-08-06 14:31:52 -0700838 if (currentDataId == -1) {
839 return;
840 }
841 if (imageUri.equals(
842 mDataAdapter.getLocalData(currentDataId).getContentUri())) {
843 updateStitchingProgress(progress);
844 }
845 }
846 });
Angus Kong6798c342013-07-16 15:14:58 -0700847 }
848 };
849
Angus Kong9f1db522013-11-09 16:25:59 -0800850 @Override
851 public Context getAndroidContext() {
852 return this;
853 }
854
855 @Override
Doris Liuf55f3c42013-11-20 00:24:46 -0800856 public int getCurrentModuleIndex() {
857 return mCurrentModeIndex;
858 }
859
860 @Override
Angus Kong9f1db522013-11-09 16:25:59 -0800861 public SurfaceTexture getPreviewBuffer() {
862 // TODO: implement this
863 return null;
864 }
865
866 @Override
867 public FrameLayout getModuleLayoutRoot() {
868 return mCameraModuleRootView;
869 }
870
871 @Override
872 public void setShutterEventsListener(ShutterEventsListener listener) {
873 // TODO: implement this
874 }
875
876 @Override
877 public void setShutterEnabled(boolean enabled) {
878 // TODO: implement this
879 }
880
881 @Override
882 public boolean isShutterEnabled() {
883 // TODO: implement this
884 return false;
885 }
886
887 @Override
888 public void startPreCaptureAnimation() {
889 // TODO: implement this
890 }
891
892 @Override
893 public void cancelPreCaptureAnimation() {
894 // TODO: implement this
895 }
896
897 @Override
898 public void startPostCaptureAnimation() {
899 // TODO: implement this
900 }
901
902 @Override
903 public void startPostCaptureAnimation(Bitmap thumbnail) {
904 // TODO: implement this
905 }
906
907 @Override
908 public void cancelPostCaptureAnimation() {
909 // TODO: implement this
910 }
911
912 @Override
Angus Kong9f1db522013-11-09 16:25:59 -0800913 public OrientationManager getOrientationManager() {
914 return mOrientationManager;
915 }
916
917 @Override
918 public LocationManager getLocationManager() {
Erin Dahlgren21c21a62013-11-19 16:37:38 -0800919 return mLocationManager;
Angus Kong9f1db522013-11-09 16:25:59 -0800920 }
921
922 @Override
923 public void lockOrientation() {
924 mOrientationManager.lockOrientation();
925 }
926
927 @Override
928 public void unlockOrientation() {
929 mOrientationManager.unlockOrientation();
930 }
931
932 @Override
Doris Liu6432cd62013-06-13 17:20:31 -0700933 public void notifyNewMedia(Uri uri) {
934 ContentResolver cr = getContentResolver();
935 String mimeType = cr.getType(uri);
936 if (mimeType.startsWith("video/")) {
Angus Kongb50b5cb2013-08-09 14:55:20 -0700937 sendBroadcast(new Intent(CameraUtil.ACTION_NEW_VIDEO, uri));
Doris Liu6432cd62013-06-13 17:20:31 -0700938 mDataAdapter.addNewVideo(cr, uri);
939 } else if (mimeType.startsWith("image/")) {
Angus Kongb50b5cb2013-08-09 14:55:20 -0700940 CameraUtil.broadcastNewPicture(this, uri);
Doris Liu6432cd62013-06-13 17:20:31 -0700941 mDataAdapter.addNewPhoto(cr, uri);
Sascha Haeberling37f36112013-08-06 14:31:52 -0700942 } else if (mimeType.startsWith("application/stitching-preview")) {
943 mDataAdapter.addNewPhoto(cr, uri);
Ruben Brunk7cfcafd2013-10-17 15:41:44 -0700944 } else if (mimeType.startsWith(PlaceholderManager.PLACEHOLDER_MIME_TYPE)) {
945 mDataAdapter.addNewPhoto(cr, uri);
Doris Liu48239f42013-03-04 22:19:10 -0800946 } else {
Doris Liu6432cd62013-06-13 17:20:31 -0700947 android.util.Log.w(TAG, "Unknown new media with MIME type:"
948 + mimeType + ", uri:" + uri);
Doris Liu48239f42013-03-04 22:19:10 -0800949 }
950 }
951
Angus Kong20fad242013-11-11 18:23:46 -0800952 @Override
Angus Kong13e87c42013-11-25 10:02:47 -0800953 public void enableKeepScreenOn(boolean enabled) {
954 if (mPaused) {
955 return;
956 }
957
958 mKeepScreenOn = enabled;
959 if (mKeepScreenOn) {
960 mMainHandler.removeMessages(MSG_CLEAR_SCREEN_ON_FLAG);
961 getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
962 } else {
963 keepScreenOnForAWhile();
964 }
965 }
966
967 @Override
Angus Kong20fad242013-11-11 18:23:46 -0800968 public CameraProvider getCameraProvider() {
969 return mCameraController;
970 }
971
Doris Liu6432cd62013-06-13 17:20:31 -0700972 private void removeData(int dataID) {
973 mDataAdapter.removeData(CameraActivity.this, dataID);
Doris Liu742cd5b2013-09-12 16:17:43 -0700974 if (mDataAdapter.getTotalNumber() > 1) {
975 showUndoDeletionBar();
976 } else {
977 // If camera preview is the only view left in filmstrip,
978 // no need to show undo bar.
Doris Liuf2c14332013-09-26 11:24:37 -0700979 mPendingDeletion = true;
Doris Liu742cd5b2013-09-12 16:17:43 -0700980 performDeletion();
981 }
Michael Kolb8872c232013-01-29 10:33:22 -0800982 }
983
Angus Kong86d36312013-01-31 18:22:44 -0800984
Michael Kolb8872c232013-01-29 10:33:22 -0800985 @Override
ztenghui0353ca22013-08-13 13:53:16 -0700986 public boolean onCreateOptionsMenu(Menu menu) {
987 // Inflate the menu items for use in the action bar
988 MenuInflater inflater = getMenuInflater();
989 inflater.inflate(R.menu.operations, menu);
990 mActionBarMenu = menu;
Mangesh Ghiwarecd2eeb02013-08-23 13:28:21 -0700991
992 // Configure the standard share action provider
993 MenuItem item = menu.findItem(R.id.action_share);
994 mStandardShareActionProvider = (ShareActionProvider) item.getActionProvider();
Mangesh Ghiware33035c12013-08-23 13:28:21 -0700995 mStandardShareActionProvider.setShareHistoryFileName("standard_share_history.xml");
Mangesh Ghiwarecd2eeb02013-08-23 13:28:21 -0700996 if (mStandardShareIntent != null) {
997 mStandardShareActionProvider.setShareIntent(mStandardShareIntent);
998 }
999
1000 // Configure the panorama share action provider
1001 item = menu.findItem(R.id.action_share_panorama);
1002 mPanoramaShareActionProvider = (ShareActionProvider) item.getActionProvider();
Mangesh Ghiware33035c12013-08-23 13:28:21 -07001003 mPanoramaShareActionProvider.setShareHistoryFileName("panorama_share_history.xml");
Mangesh Ghiwarecd2eeb02013-08-23 13:28:21 -07001004 if (mPanoramaShareIntent != null) {
1005 mPanoramaShareActionProvider.setShareIntent(mPanoramaShareIntent);
1006 }
1007
Seth Raphaelcbd82672013-11-05 10:12:36 -08001008 mStandardShareActionProvider.setOnShareTargetSelectedListener(this);
1009 mPanoramaShareActionProvider.setOnShareTargetSelectedListener(this);
1010
ztenghui0353ca22013-08-13 13:53:16 -07001011 return super.onCreateOptionsMenu(menu);
1012 }
1013
1014 @Override
1015 public boolean onOptionsItemSelected(MenuItem item) {
Angus Kong62848152013-11-08 17:25:29 -08001016 int currentDataId = mFilmstripController.getCurrentId();
Sascha Haeberling6f64b502013-08-14 16:23:18 -07001017 if (currentDataId < 0) {
1018 return false;
1019 }
1020 final LocalData localData = mDataAdapter.getLocalData(currentDataId);
1021
ztenghui0353ca22013-08-13 13:53:16 -07001022 // Handle presses on the action bar items
1023 switch (item.getItemId()) {
Alan Newberger3f969c12013-08-23 10:10:30 -07001024 case android.R.id.home:
1025 // ActionBar's Up/Home button was clicked
Mangesh Ghiware30968d02013-10-02 14:38:12 -07001026 try {
Alan Newberger761306f2013-10-30 12:51:21 -07001027 startActivity(IntentHelper.getGalleryIntent(this));
Mangesh Ghiware30968d02013-10-02 14:38:12 -07001028 return true;
1029 } catch (ActivityNotFoundException e) {
Alan Newberger761306f2013-10-30 12:51:21 -07001030 Log.w(TAG, "Failed to launch gallery activity, closing");
Mangesh Ghiware30968d02013-10-02 14:38:12 -07001031 finish();
Mangesh Ghiware5df64b02013-09-18 18:25:26 -07001032 }
ztenghui0353ca22013-08-13 13:53:16 -07001033 case R.id.action_delete:
Seth Raphaelcbd82672013-11-05 10:12:36 -08001034 UsageStatistics.onEvent(UsageStatistics.COMPONENT_CAMERA,
1035 UsageStatistics.ACTION_DELETE, null, 0,
1036 UsageStatistics.hashFileName(fileNameFromDataID(currentDataId)));
Angus Konge857cc92013-08-19 14:46:20 -07001037 removeData(currentDataId);
ztenghui0353ca22013-08-13 13:53:16 -07001038 return true;
1039 case R.id.action_edit:
Seth Raphaelcbd82672013-11-05 10:12:36 -08001040 UsageStatistics.onEvent(UsageStatistics.COMPONENT_CAMERA,
1041 UsageStatistics.ACTION_EDIT, null, 0,
1042 UsageStatistics.hashFileName(fileNameFromDataID(currentDataId)));
Sascha Haeberling88ef7662013-08-15 17:19:22 -07001043 launchEditor(localData);
ztenghui0353ca22013-08-13 13:53:16 -07001044 return true;
nicolasroard08193042013-08-20 09:19:23 -07001045 case R.id.action_trim: {
ztenghui6b920322013-08-16 16:21:22 -07001046 // This is going to be handled by the Gallery app.
1047 Intent intent = new Intent(ACTION_TRIM_VIDEO);
Angus Kong62848152013-11-08 17:25:29 -08001048 LocalData currentData = mDataAdapter.getLocalData(mFilmstripController.getCurrentId());
ztenghui6b920322013-08-16 16:21:22 -07001049 intent.setData(currentData.getContentUri());
1050 // We need the file path to wrap this into a RandomAccessFile.
1051 intent.putExtra(MEDIA_ITEM_PATH, currentData.getPath());
Sascha Haeberlingb7639c62013-09-09 14:42:43 -07001052 startActivityForResult(intent, REQ_CODE_DONT_SWITCH_TO_PREVIEW);
ztenghui0353ca22013-08-13 13:53:16 -07001053 return true;
nicolasroard08193042013-08-20 09:19:23 -07001054 }
ztenghui0353ca22013-08-13 13:53:16 -07001055 case R.id.action_rotate_ccw:
ztenghuia16e7b52013-08-23 11:47:56 -07001056 localData.rotate90Degrees(this, mDataAdapter, currentDataId, false);
ztenghui0353ca22013-08-13 13:53:16 -07001057 return true;
1058 case R.id.action_rotate_cw:
ztenghuia16e7b52013-08-23 11:47:56 -07001059 localData.rotate90Degrees(this, mDataAdapter, currentDataId, true);
ztenghui0353ca22013-08-13 13:53:16 -07001060 return true;
nicolasroard19ab7252013-09-18 16:54:05 -07001061 case R.id.action_crop: {
Seth Raphaelcbd82672013-11-05 10:12:36 -08001062 UsageStatistics.onEvent(UsageStatistics.COMPONENT_CAMERA,
1063 UsageStatistics.ACTION_CROP, null, 0,
1064 UsageStatistics.hashFileName(fileNameFromDataID(currentDataId)));
nicolasroard19ab7252013-09-18 16:54:05 -07001065 Intent intent = new Intent(CropActivity.CROP_ACTION);
1066 intent.setClass(this, CropActivity.class);
1067 intent.setDataAndType(localData.getContentUri(), localData.getMimeType())
1068 .setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
1069 startActivityForResult(intent, REQ_CODE_DONT_SWITCH_TO_PREVIEW);
ztenghui0353ca22013-08-13 13:53:16 -07001070 return true;
nicolasroard19ab7252013-09-18 16:54:05 -07001071 }
nicolasroard08193042013-08-20 09:19:23 -07001072 case R.id.action_setas: {
1073 Intent intent = new Intent(Intent.ACTION_ATTACH_DATA)
1074 .setDataAndType(localData.getContentUri(),
1075 localData.getMimeType())
1076 .setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
1077 intent.putExtra("mimeType", intent.getType());
Sascha Haeberlingb7639c62013-09-09 14:42:43 -07001078 startActivityForResult(Intent.createChooser(
1079 intent, getString(R.string.set_as)), REQ_CODE_DONT_SWITCH_TO_PREVIEW);
ztenghui0353ca22013-08-13 13:53:16 -07001080 return true;
nicolasroard08193042013-08-20 09:19:23 -07001081 }
ztenghui0353ca22013-08-13 13:53:16 -07001082 case R.id.action_details:
Sascha Haeberling6f64b502013-08-14 16:23:18 -07001083 (new AsyncTask<Void, Void, MediaDetails>() {
1084 @Override
1085 protected MediaDetails doInBackground(Void... params) {
1086 return localData.getMediaDetails(CameraActivity.this);
1087 }
1088
1089 @Override
1090 protected void onPostExecute(MediaDetails mediaDetails) {
Sascha Haeberling64cea6a2013-10-10 20:12:07 -07001091 if (mediaDetails != null) {
1092 DetailsDialog.create(CameraActivity.this, mediaDetails).show();
1093 }
Sascha Haeberling6f64b502013-08-14 16:23:18 -07001094 }
1095 }).execute();
ztenghui0353ca22013-08-13 13:53:16 -07001096 return true;
1097 case R.id.action_show_on_map:
Sascha Haeberlingfae11a12013-08-15 14:29:49 -07001098 double[] latLong = localData.getLatLong();
1099 if (latLong != null) {
Sascha Haeberlinga5a08d72013-09-11 20:30:52 -07001100 CameraUtil.showOnMap(this, latLong);
Sascha Haeberlingfae11a12013-08-15 14:29:49 -07001101 }
ztenghui0353ca22013-08-13 13:53:16 -07001102 return true;
1103 default:
1104 return super.onOptionsItemSelected(item);
1105 }
1106 }
1107
ztenghuifd43e3b2013-09-03 11:30:11 -07001108 private boolean isCaptureIntent() {
1109 if (MediaStore.ACTION_VIDEO_CAPTURE.equals(getIntent().getAction())
1110 || MediaStore.ACTION_IMAGE_CAPTURE.equals(getIntent().getAction())
1111 || MediaStore.ACTION_IMAGE_CAPTURE_SECURE.equals(getIntent().getAction())) {
1112 return true;
1113 } else {
1114 return false;
1115 }
1116 }
1117
ztenghui0353ca22013-08-13 13:53:16 -07001118 @Override
Doris Liu6432cd62013-06-13 17:20:31 -07001119 public void onCreate(Bundle state) {
1120 super.onCreate(state);
Sascha Haeberling048bf4d2013-10-06 17:49:51 -07001121 GcamHelper.init(getContentResolver());
1122
ztenghui50df4702013-08-13 15:53:57 -07001123 getWindow().requestFeature(Window.FEATURE_ACTION_BAR);
Doris Liu1c94b7d2013-11-09 19:13:44 -08001124 setContentView(R.layout.activity_main);
ztenghuifa9e2cc2013-08-09 17:37:15 -07001125 mActionBar = getActionBar();
Doris Liuaa874422013-09-18 19:43:12 -07001126 mActionBar.addOnMenuVisibilityListener(this);
Angus Kong20fad242013-11-11 18:23:46 -08001127 mMainHandler = new MainHandler(getMainLooper());
1128 mCameraController =
1129 new CameraController(this, this, mMainHandler,
1130 CameraManagerFactory.getAndroidCameraManager());
1131 // TODO: Try to move all the resources allocation to happen as soon as
1132 // possible so we can call module.init() at the earliest time.
1133 mModuleManager = new ModuleManagerImpl();
Angus Kong612321f2013-11-18 16:17:43 -08001134 ModulesInfo.setupModules(this, mModuleManager);
ztenghuifa9e2cc2013-08-09 17:37:15 -07001135
Doris Liu70576b62013-11-14 20:30:33 -08001136 mModeListView = (ModeListView) findViewById(R.id.mode_list_layout);
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);
Doris Liub84b9732013-06-18 17:14:26 -07001162 }
Angus Kong653c43b2013-08-21 18:28:43 -07001163 mAboveFilmstripControlLayout =
1164 (FrameLayout) findViewById(R.id.camera_above_filmstrip_layout);
1165 mAboveFilmstripControlLayout.setFitsSystemWindows(true);
Sascha Haeberling5199c202013-09-05 17:10:19 -07001166 // Hide action bar first since we are in full screen mode first, and
1167 // switch the system UI to lights-out mode.
Doris Liuaa874422013-09-18 19:43:12 -07001168 this.setSystemBarsVisibility(false);
Angus Konged15d1a2013-08-19 15:06:12 -07001169 mPanoramaManager = AppManagerFactory.getInstance(this)
1170 .getPanoramaStitchingManager();
Ruben Brunk7cfcafd2013-10-17 15:41:44 -07001171 mPlaceholderManager = AppManagerFactory.getInstance(this)
1172 .getGcamProcessingManager();
Angus Kong6798c342013-07-16 15:14:58 -07001173 mPanoramaManager.addTaskListener(mStitchingListener);
Ruben Brunk7cfcafd2013-10-17 15:41:44 -07001174 mPlaceholderManager.addTaskListener(mPlaceholderListener);
Doris Liu6432cd62013-06-13 17:20:31 -07001175 LayoutInflater inflater = getLayoutInflater();
1176 View rootLayout = inflater.inflate(R.layout.camera, null, false);
Angus Kong9f1db522013-11-09 16:25:59 -08001177 mCameraModuleRootView = (FrameLayout) rootLayout.findViewById(R.id.camera_app_root);
ztenghuifa9e2cc2013-08-09 17:37:15 -07001178 mPanoStitchingPanel = findViewById(R.id.pano_stitching_progress_panel);
Sascha Haeberling37f36112013-08-06 14:31:52 -07001179 mBottomProgress = (ProgressBar) findViewById(R.id.pano_stitching_progress_bar);
Angus Kong8e5e4ee2013-07-30 11:36:00 -07001180 mCameraPreviewData = new CameraPreviewData(rootLayout,
Angus Kong62848152013-11-08 17:25:29 -08001181 FilmstripImageData.SIZE_FULL,
1182 FilmstripImageData.SIZE_FULL);
Sascha Haeberling37f36112013-08-06 14:31:52 -07001183 // Put a CameraPreviewData at the first position.
Angus Kong8e5e4ee2013-07-30 11:36:00 -07001184 mWrappedDataAdapter = new FixedFirstDataAdapter(
1185 new CameraDataAdapter(new ColorDrawable(
1186 getResources().getColor(R.color.photo_placeholder))),
1187 mCameraPreviewData);
Angus Kong62848152013-11-08 17:25:29 -08001188 mFilmstripController = ((FilmstripView) findViewById(R.id.filmstrip_view)).getController();
1189 mFilmstripController.setViewGap(
Doris Liu6432cd62013-06-13 17:20:31 -07001190 getResources().getDimensionPixelSize(R.dimen.camera_film_strip_gap));
Sascha Haeberlingf1f51862013-07-31 11:28:21 -07001191 mPanoramaViewHelper = new PanoramaViewHelper(this);
1192 mPanoramaViewHelper.onCreate();
Angus Kong62848152013-11-08 17:25:29 -08001193 mFilmstripController.setPanoramaViewHelper(mPanoramaViewHelper);
Doris Liu6432cd62013-06-13 17:20:31 -07001194 // Set up the camera preview first so the preview shows up ASAP.
Angus Kong62848152013-11-08 17:25:29 -08001195 mFilmstripController.setListener(mFilmStripListener);
Sascha Haeberling2654dd92013-08-28 15:28:57 -07001196
Doris Liuf55f3c42013-11-20 00:24:46 -08001197 // TODO: Remove the 3rd parameter once mCameraModuleRoot is moved out of filmstrip
1198 mCameraAppUI = new CameraAppUI(this,
1199 (MainActivityLayout) findViewById(R.id.activity_root_view),
1200 mCameraModuleRootView,
1201 isSecureCamera(), isCaptureIntent());
1202
Erin Dahlgren357b7672013-11-20 17:38:14 -08001203 mSettingsManager = new SettingsManager(this, null, mCameraController.getNumberOfCameras());
Erin Dahlgren21c21a62013-11-19 16:37:38 -08001204
1205 mLocationManager = new LocationManager(this,
1206 new LocationManager.Listener() {
1207 @Override
1208 public void showGpsOnScreenIndicator(boolean hasSignal) {
1209 }
1210
1211 @Override
1212 public void hideGpsOnScreenIndicator() {
1213 }
1214 });
1215
Erin Dahlgren357b7672013-11-20 17:38:14 -08001216 mSettingsController = new SettingsController(this, mSettingsManager, mLocationManager);
1217
1218 int modeIndex = -1;
1219 if (MediaStore.INTENT_ACTION_VIDEO_CAMERA.equals(getIntent().getAction())
1220 || MediaStore.ACTION_VIDEO_CAPTURE.equals(getIntent().getAction())) {
1221 modeIndex = ModeListView.MODE_VIDEO;
1222 } else if (MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA.equals(getIntent().getAction())
1223 || MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE.equals(getIntent()
1224 .getAction())) {
1225 modeIndex = ModeListView.MODE_PHOTO;
1226 if (mSettingsManager.getInt(new StartupModuleSetting())
1227 == ModeListView.MODE_GCAM && GcamHelper.hasGcamCapture()) {
1228 modeIndex = ModeListView.MODE_GCAM;
1229 }
1230 } else if (MediaStore.ACTION_IMAGE_CAPTURE.equals(getIntent().getAction())
1231 || MediaStore.ACTION_IMAGE_CAPTURE_SECURE.equals(getIntent().getAction())) {
1232 modeIndex = ModeListView.MODE_PHOTO;
1233 } else {
1234 // If the activity has not been started using an explicit intent,
1235 // read the module index from the last time the user changed modes
1236 modeIndex = mSettingsManager.getInt(new StartupModuleSetting());
1237 if ((modeIndex == ModeListView.MODE_GCAM &&
1238 !GcamHelper.hasGcamCapture()) || modeIndex < 0) {
1239 modeIndex = ModeListView.MODE_PHOTO;
1240 }
1241 }
1242
1243 mOrientationManager = new OrientationManagerImpl(this);
1244 mOrientationManager.addOnOrientationChangeListener(mMainHandler, this);
Erin Dahlgrenc120b0f2013-11-19 10:53:49 -08001245
1246 setModuleFromModeIndex(modeIndex);
Doris Liuf55f3c42013-11-20 00:24:46 -08001247
1248 // TODO: Remove this when refactor is done.
1249 if (modeIndex == ModulesInfo.MODULE_PHOTO ||
1250 modeIndex == ModulesInfo.MODULE_VIDEO) {
1251 mCameraAppUI.prepareModuleUI();
1252 }
Angus Kong13e87c42013-11-25 10:02:47 -08001253 mCurrentModule.init(this, isSecureCamera(), isCaptureIntent());
Sascha Haeberling37f36112013-08-06 14:31:52 -07001254
1255 if (!mSecureCamera) {
1256 mDataAdapter = mWrappedDataAdapter;
Angus Kong62848152013-11-08 17:25:29 -08001257 mFilmstripController.setDataAdapter(mDataAdapter);
Angus Konga7194602013-09-06 17:20:15 -07001258 if (!isCaptureIntent()) {
1259 mDataAdapter.requestLoad(getContentResolver());
1260 }
Sascha Haeberling37f36112013-08-06 14:31:52 -07001261 } else {
Sascha Haeberlinga5a08d72013-09-11 20:30:52 -07001262 // Put a lock placeholder as the last image by setting its date to
1263 // 0.
Sascha Haeberling37f36112013-08-06 14:31:52 -07001264 ImageView v = (ImageView) getLayoutInflater().inflate(
1265 R.layout.secure_album_placeholder, null);
Angus Kong690dc472013-09-21 14:48:51 -07001266 v.setOnClickListener(new View.OnClickListener() {
1267 @Override
1268 public void onClick(View view) {
Alan Newberger761306f2013-10-30 12:51:21 -07001269 try {
Seth Raphaelcbd82672013-11-05 10:12:36 -08001270 UsageStatistics.onEvent(UsageStatistics.COMPONENT_CAMERA,
1271 UsageStatistics.ACTION_GALLERY, null);
Alan Newberger761306f2013-10-30 12:51:21 -07001272 startActivity(IntentHelper.getGalleryIntent(CameraActivity.this));
1273 } catch (ActivityNotFoundException e) {
1274 Log.w(TAG, "Failed to launch gallery activity, closing");
1275 }
Angus Kong690dc472013-09-21 14:48:51 -07001276 finish();
1277 }
1278 });
Sascha Haeberling37f36112013-08-06 14:31:52 -07001279 mDataAdapter = new FixedLastDataAdapter(
1280 mWrappedDataAdapter,
Angus Kongbd260692013-08-07 14:52:56 -07001281 new SimpleViewData(
Sascha Haeberling37f36112013-08-06 14:31:52 -07001282 v,
1283 v.getDrawable().getIntrinsicWidth(),
1284 v.getDrawable().getIntrinsicHeight(),
1285 0, 0));
1286 // Flush out all the original data.
1287 mDataAdapter.flush();
Angus Kong62848152013-11-08 17:25:29 -08001288 mFilmstripController.setDataAdapter(mDataAdapter);
Sascha Haeberling37f36112013-08-06 14:31:52 -07001289 }
Mangesh Ghiwarea5682ab2013-09-19 09:24:23 -07001290
1291 setupNfcBeamPush();
ztenghui064d6002013-09-05 15:47:58 -07001292
Doris Liu2b86d872013-09-26 15:23:41 -07001293 mLocalImagesObserver = new LocalMediaObserver();
1294 mLocalVideosObserver = new LocalMediaObserver();
ztenghui064d6002013-09-05 15:47:58 -07001295
1296 getContentResolver().registerContentObserver(
1297 MediaStore.Images.Media.EXTERNAL_CONTENT_URI, true,
1298 mLocalImagesObserver);
1299 getContentResolver().registerContentObserver(
1300 MediaStore.Video.Media.EXTERNAL_CONTENT_URI, true,
1301 mLocalVideosObserver);
Michael Kolb8872c232013-01-29 10:33:22 -08001302 }
1303
Doris Liu6432cd62013-06-13 17:20:31 -07001304 private void setRotationAnimation() {
Michael Kolb08650182013-02-25 19:43:56 -08001305 int rotationAnimation = WindowManager.LayoutParams.ROTATION_ANIMATION_ROTATE;
Doris Liu6432cd62013-06-13 17:20:31 -07001306 rotationAnimation = WindowManager.LayoutParams.ROTATION_ANIMATION_CROSSFADE;
Michael Kolb08650182013-02-25 19:43:56 -08001307 Window win = getWindow();
1308 WindowManager.LayoutParams winParams = win.getAttributes();
1309 winParams.rotationAnimation = rotationAnimation;
1310 win.setAttributes(winParams);
1311 }
1312
Michael Kolb8872c232013-01-29 10:33:22 -08001313 @Override
Michael Kolb8872c232013-01-29 10:33:22 -08001314 public void onUserInteraction() {
1315 super.onUserInteraction();
Angus Kong13e87c42013-11-25 10:02:47 -08001316 if (!isFinishing()) {
1317 keepScreenOnForAWhile();
1318 }
Michael Kolb8872c232013-01-29 10:33:22 -08001319 }
1320
1321 @Override
Doris Liu742cd5b2013-09-12 16:17:43 -07001322 public boolean dispatchTouchEvent(MotionEvent ev) {
1323 boolean result = super.dispatchTouchEvent(ev);
1324 if (ev.getActionMasked() == MotionEvent.ACTION_DOWN) {
1325 // Real deletion is postponed until the next user interaction after
1326 // the gesture that triggers deletion. Until real deletion is performed,
1327 // users can click the undo button to bring back the image that they
1328 // chose to delete.
1329 if (mPendingDeletion && !mIsUndoingDeletion) {
Angus Kong20fad242013-11-11 18:23:46 -08001330 performDeletion();
Doris Liu742cd5b2013-09-12 16:17:43 -07001331 }
1332 }
1333 return result;
1334 }
1335
1336 @Override
Doris Liu6432cd62013-06-13 17:20:31 -07001337 public void onPause() {
Erin Dahlgrenc120b0f2013-11-19 10:53:49 -08001338 mPaused = true;
1339
Doris Liuf2c14332013-09-26 11:24:37 -07001340 // Delete photos that are pending deletion
1341 performDeletion();
Angus Kong20fad242013-11-11 18:23:46 -08001342 // TODO: call mCurrentModule.pause() instead after all the modules
1343 // support pause().
Angus Kongc4e66562013-11-22 23:03:21 -08001344 mCurrentModule.pause();
Angus Kong9f1db522013-11-09 16:25:59 -08001345 mOrientationManager.pause();
Angus Kong20fad242013-11-11 18:23:46 -08001346 // Close the camera and wait for the operation done.
1347 mCameraController.closeCamera();
Doris Liu2b86d872013-09-26 15:23:41 -07001348
1349 mLocalImagesObserver.setActivityPaused(true);
1350 mLocalVideosObserver.setActivityPaused(true);
Angus Kong13e87c42013-11-25 10:02:47 -08001351 resetScreenOn();
Angus Kongc4e66562013-11-22 23:03:21 -08001352 super.onPause();
Doris Liu6432cd62013-06-13 17:20:31 -07001353 }
1354
1355 @Override
Sascha Haeberlingb7639c62013-09-09 14:42:43 -07001356 protected void onActivityResult(int requestCode, int resultCode, Intent data) {
ztenghui064d6002013-09-05 15:47:58 -07001357 if (requestCode == REQ_CODE_DONT_SWITCH_TO_PREVIEW) {
Sascha Haeberlingb7639c62013-09-09 14:42:43 -07001358 mResetToPreviewOnResume = false;
1359 } else {
1360 super.onActivityResult(requestCode, resultCode, data);
1361 }
1362 }
1363
1364 @Override
Doris Liu6432cd62013-06-13 17:20:31 -07001365 public void onResume() {
Erin Dahlgrenc120b0f2013-11-19 10:53:49 -08001366 mPaused = false;
1367
Angus Kongce2b9492013-09-05 17:49:06 -07001368 // TODO: Handle this in OrientationManager.
Sascha Haeberlinga5a08d72013-09-11 20:30:52 -07001369 // Auto-rotate off
Doris Liu6432cd62013-06-13 17:20:31 -07001370 if (Settings.System.getInt(getContentResolver(),
Sascha Haeberlinga5a08d72013-09-11 20:30:52 -07001371 Settings.System.ACCELEROMETER_ROTATION, 0) == 0) {
Doris Liu6432cd62013-06-13 17:20:31 -07001372 setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
1373 mAutoRotateScreen = false;
1374 } else {
1375 setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR);
1376 mAutoRotateScreen = true;
1377 }
Seth Raphaelcbd82672013-11-05 10:12:36 -08001378
1379 UsageStatistics.onEvent(UsageStatistics.COMPONENT_CAMERA,
1380 UsageStatistics.ACTION_FOREGROUNDED, this.getClass().getSimpleName());
1381
Angus Kong9f1db522013-11-09 16:25:59 -08001382 mOrientationManager.resume();
Doris Liu6432cd62013-06-13 17:20:31 -07001383 super.onResume();
Angus Kongc4e66562013-11-22 23:03:21 -08001384 mCurrentModule.resume();
Doris Liu6432cd62013-06-13 17:20:31 -07001385
Angus Kong6798c342013-07-16 15:14:58 -07001386 setSwipingEnabled(true);
Sascha Haeberlingb7639c62013-09-09 14:42:43 -07001387
1388 if (mResetToPreviewOnResume) {
1389 // Go to the preview on resume.
Angus Kong62848152013-11-08 17:25:29 -08001390 mFilmstripController.goToFirstItem();
Sascha Haeberlingb7639c62013-09-09 14:42:43 -07001391 }
1392 // Default is showing the preview, unless disabled by explicitly
1393 // starting an activity we want to return from to the filmstrip rather
1394 // than the preview.
1395 mResetToPreviewOnResume = true;
ztenghui064d6002013-09-05 15:47:58 -07001396
Doris Liu2b86d872013-09-26 15:23:41 -07001397 if (mLocalVideosObserver.isMediaDataChangedDuringPause()
1398 || mLocalImagesObserver.isMediaDataChangedDuringPause()) {
Angus Kong2d5c7472013-10-12 23:48:46 -07001399 if (!mSecureCamera) {
1400 // If it's secure camera, requestLoad() should not be called
1401 // as it will load all the data.
1402 mDataAdapter.requestLoad(getContentResolver());
1403 }
ztenghui064d6002013-09-05 15:47:58 -07001404 }
Doris Liu2b86d872013-09-26 15:23:41 -07001405 mLocalImagesObserver.setActivityPaused(false);
1406 mLocalVideosObserver.setActivityPaused(false);
Doris Liu70576b62013-11-14 20:30:33 -08001407
Angus Kong13e87c42013-11-25 10:02:47 -08001408 keepScreenOnForAWhile();
1409
Doris Liu70576b62013-11-14 20:30:33 -08001410 mModeListView.startAccordionAnimation();
Angus Kong6798c342013-07-16 15:14:58 -07001411 }
1412
1413 @Override
1414 public void onStart() {
1415 super.onStart();
Sascha Haeberlingf1f51862013-07-31 11:28:21 -07001416 mPanoramaViewHelper.onStart();
1417 }
1418
1419 @Override
1420 protected void onStop() {
Sascha Haeberlingf1f51862013-07-31 11:28:21 -07001421 mPanoramaViewHelper.onStop();
Angus Kong0e57fc12013-11-18 13:21:07 -08001422
1423 CameraManagerFactory.recycle();
1424 super.onStop();
Doris Liu6432cd62013-06-13 17:20:31 -07001425 }
1426
1427 @Override
1428 public void onDestroy() {
Sascha Haeberlinga5a08d72013-09-11 20:30:52 -07001429 if (mSecureCamera) {
1430 unregisterReceiver(mScreenOffReceiver);
1431 }
ztenghui064d6002013-09-05 15:47:58 -07001432 getContentResolver().unregisterContentObserver(mLocalImagesObserver);
1433 getContentResolver().unregisterContentObserver(mLocalVideosObserver);
Doris Liu6432cd62013-06-13 17:20:31 -07001434 super.onDestroy();
1435 }
1436
1437 @Override
1438 public void onConfigurationChanged(Configuration config) {
1439 super.onConfigurationChanged(config);
1440 mCurrentModule.onConfigurationChanged(config);
1441 }
1442
1443 @Override
1444 public boolean onKeyDown(int keyCode, KeyEvent event) {
Angus Kong62848152013-11-08 17:25:29 -08001445 if (mFilmstripController.inCameraFullscreen()) {
Doris Liudba16ae2013-10-03 15:31:40 -07001446 if (mCurrentModule.onKeyDown(keyCode, event)) {
Sascha Haeberlinga5a08d72013-09-11 20:30:52 -07001447 return true;
1448 }
Doris Liudba16ae2013-10-03 15:31:40 -07001449 // Prevent software keyboard or voice search from showing up.
1450 if (keyCode == KeyEvent.KEYCODE_SEARCH
1451 || keyCode == KeyEvent.KEYCODE_MENU) {
1452 if (event.isLongPress()) {
1453 return true;
1454 }
1455 }
Doris Liu6432cd62013-06-13 17:20:31 -07001456 }
Doris Liu6432cd62013-06-13 17:20:31 -07001457
1458 return super.onKeyDown(keyCode, event);
1459 }
1460
1461 @Override
1462 public boolean onKeyUp(int keyCode, KeyEvent event) {
Angus Kong62848152013-11-08 17:25:29 -08001463 if (mFilmstripController.inCameraFullscreen() && mCurrentModule.onKeyUp(keyCode, event)) {
Sascha Haeberlinga5a08d72013-09-11 20:30:52 -07001464 return true;
1465 }
Doris Liu6432cd62013-06-13 17:20:31 -07001466 return super.onKeyUp(keyCode, event);
1467 }
1468
Alan Newberger5f6b50d2013-08-30 15:19:48 -07001469 @Override
1470 public void onBackPressed() {
Angus Kong62848152013-11-08 17:25:29 -08001471 if (!mFilmstripController.inCameraFullscreen()) {
1472 mFilmstripController.goToFirstItem();
Alan Newberger5f6b50d2013-08-30 15:19:48 -07001473 } else if (!mCurrentModule.onBackPressed()) {
1474 super.onBackPressed();
1475 }
1476 }
1477
Doris Liu6432cd62013-06-13 17:20:31 -07001478 public boolean isAutoRotateScreen() {
1479 return mAutoRotateScreen;
1480 }
1481
1482 protected void updateStorageSpace() {
Angus Kong2dcc0a92013-09-25 13:00:08 -07001483 mStorageSpaceBytes = Storage.getAvailableSpace();
Doris Liu6432cd62013-06-13 17:20:31 -07001484 }
1485
Angus Kong2dcc0a92013-09-25 13:00:08 -07001486 protected long getStorageSpaceBytes() {
1487 return mStorageSpaceBytes;
Doris Liu6432cd62013-06-13 17:20:31 -07001488 }
1489
1490 protected void updateStorageSpaceAndHint() {
1491 updateStorageSpace();
Angus Kong2dcc0a92013-09-25 13:00:08 -07001492 updateStorageHint(mStorageSpaceBytes);
Doris Liu6432cd62013-06-13 17:20:31 -07001493 }
1494
1495 protected void updateStorageHint(long storageSpace) {
1496 String message = null;
1497 if (storageSpace == Storage.UNAVAILABLE) {
1498 message = getString(R.string.no_storage);
1499 } else if (storageSpace == Storage.PREPARING) {
1500 message = getString(R.string.preparing_sd);
1501 } else if (storageSpace == Storage.UNKNOWN_SIZE) {
1502 message = getString(R.string.access_sd_fail);
Angus Kong2dcc0a92013-09-25 13:00:08 -07001503 } else if (storageSpace <= Storage.LOW_STORAGE_THRESHOLD_BYTES) {
Doris Liu6432cd62013-06-13 17:20:31 -07001504 message = getString(R.string.spaceIsLow_content);
1505 }
1506
1507 if (message != null) {
1508 if (mStorageHint == null) {
1509 mStorageHint = OnScreenHint.makeText(this, message);
1510 } else {
1511 mStorageHint.setText(message);
1512 }
1513 mStorageHint.show();
1514 } else if (mStorageHint != null) {
1515 mStorageHint.cancel();
1516 mStorageHint = null;
1517 }
1518 }
1519
1520 protected void setResultEx(int resultCode) {
1521 mResultCodeForTesting = resultCode;
1522 setResult(resultCode);
1523 }
1524
1525 protected void setResultEx(int resultCode, Intent data) {
1526 mResultCodeForTesting = resultCode;
1527 mResultDataForTesting = data;
1528 setResult(resultCode, data);
1529 }
1530
1531 public int getResultCode() {
1532 return mResultCodeForTesting;
1533 }
1534
1535 public Intent getResultData() {
1536 return mResultDataForTesting;
1537 }
1538
1539 public boolean isSecureCamera() {
1540 return mSecureCamera;
Michael Kolb8872c232013-01-29 10:33:22 -08001541 }
1542
1543 @Override
Erin Dahlgrenc120b0f2013-11-19 10:53:49 -08001544 public boolean isPaused() {
1545 return mPaused;
1546 }
1547
1548 @Override
1549 public void onModeSelected(int modeIndex) {
1550 if (mCurrentModeIndex == modeIndex) {
Sascha Haeberlinga5a08d72013-09-11 20:30:52 -07001551 return;
1552 }
Doris Liu6432cd62013-06-13 17:20:31 -07001553
Doris Liuf55f3c42013-11-20 00:24:46 -08001554 if (modeIndex == ModeListView.MODE_SETTING) {
1555 onSettingsSelected();
1556 return;
1557 }
1558
Erin Dahlgrenc120b0f2013-11-19 10:53:49 -08001559 CameraHolder.instance().keep();
Doris Liu6432cd62013-06-13 17:20:31 -07001560 closeModule(mCurrentModule);
Doris Liuf55f3c42013-11-20 00:24:46 -08001561 int oldModuleIndex = mCurrentModeIndex;
Erin Dahlgrenc120b0f2013-11-19 10:53:49 -08001562 setModuleFromModeIndex(modeIndex);
Doris Liuf55f3c42013-11-20 00:24:46 -08001563
1564 // TODO: The following check is temporary for quick switch between video and photo.
1565 // When the refactor is done, similar logic will be applied to all modules.
1566 if (mCurrentModeIndex == ModulesInfo.MODULE_PHOTO
1567 || mCurrentModeIndex == ModulesInfo.MODULE_VIDEO) {
1568 if (oldModuleIndex != ModulesInfo.MODULE_PHOTO
1569 && oldModuleIndex != ModulesInfo.MODULE_VIDEO) {
1570 mCameraAppUI.prepareModuleUI();
1571 } else {
1572 mCameraAppUI.clearModuleUI();
1573 }
1574 } else {
1575 // This is the old way of removing all views in CameraRootView. Will
1576 // be deprecated soon. It is here to make sure modules that haven't
1577 // been refactored can still function.
1578 mCameraAppUI.clearCameraUI();
1579 }
1580
Sascha Haeberling2654dd92013-08-28 15:28:57 -07001581 openModule(mCurrentModule);
1582 mCurrentModule.onOrientationChanged(mLastRawOrientation);
Angus Kongfd4fc0e2013-11-07 15:38:09 -08001583 if (mMediaSaver != null) {
1584 mCurrentModule.onMediaSaverAvailable(mMediaSaver);
Sascha Haeberling2654dd92013-08-28 15:28:57 -07001585 }
Sascha Haeberling2654dd92013-08-28 15:28:57 -07001586 // Store the module index so we can use it the next time the Camera
1587 // starts up.
1588 SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
Erin Dahlgrenc120b0f2013-11-19 10:53:49 -08001589 prefs.edit().putInt(CameraSettings.KEY_STARTUP_MODULE_INDEX, modeIndex).apply();
1590 }
1591
Doris Liuf55f3c42013-11-20 00:24:46 -08001592 public void onSettingsSelected() {
Erin Dahlgrenc120b0f2013-11-19 10:53:49 -08001593 // Temporary until we finalize the touch flow.
1594 LayoutInflater inflater = getLayoutInflater();
1595 SettingsView settingsView = (SettingsView) inflater.inflate(R.layout.settings_list_layout,
1596 null, false);
Erin Dahlgren357b7672013-11-20 17:38:14 -08001597 settingsView.setSettingsListener(mSettingsController);
Erin Dahlgrenc120b0f2013-11-19 10:53:49 -08001598 PopupWindow popup = new PopupWindow(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
1599 popup.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
1600 popup.setOutsideTouchable(true);
1601 popup.setFocusable(true);
1602 popup.setContentView(settingsView);
1603 popup.showAtLocation(mModeListView.getRootView(), Gravity.CENTER, 0, 0);
Sascha Haeberling2654dd92013-08-28 15:28:57 -07001604 }
1605
1606 /**
Sascha Haeberlinga5a08d72013-09-11 20:30:52 -07001607 * Sets the mCurrentModuleIndex, creates a new module instance for the given
1608 * index an sets it as mCurrentModule.
Sascha Haeberling2654dd92013-08-28 15:28:57 -07001609 */
Erin Dahlgrenc120b0f2013-11-19 10:53:49 -08001610 private void setModuleFromModeIndex(int modeIndex) {
1611 ModuleManagerImpl.ModuleAgent agent = mModuleManager.getModuleAgent(modeIndex);
Angus Kong20fad242013-11-11 18:23:46 -08001612 if (agent == null) {
1613 return;
Doris Liu6432cd62013-06-13 17:20:31 -07001614 }
Angus Kong20fad242013-11-11 18:23:46 -08001615 if (!agent.requestAppForCamera()) {
1616 mCameraController.closeCamera();
1617 }
Erin Dahlgrenc120b0f2013-11-19 10:53:49 -08001618 mCurrentModeIndex = agent.getModuleId();
Angus Kong13e87c42013-11-25 10:02:47 -08001619 mCurrentModule = (CameraModule) agent.createModule(this);
Michael Kolb8872c232013-01-29 10:33:22 -08001620 }
1621
Erin Dahlgrenc120b0f2013-11-19 10:53:49 -08001622 @Override
1623 public SettingsManager getSettingsManager() {
1624 return mSettingsManager;
1625 }
1626
Angus Kongc4e66562013-11-22 23:03:21 -08001627 @Override
1628 public CameraServices getServices() {
1629 return (CameraServices) getApplication();
1630 }
1631
Erin Dahlgren357b7672013-11-20 17:38:14 -08001632 @Override
1633 public SettingsController getSettingsController() {
1634 return mSettingsController;
1635 }
1636
Sascha Haeberling88ef7662013-08-15 17:19:22 -07001637 /**
1638 * Launches an ACTION_EDIT intent for the given local data item.
1639 */
1640 public void launchEditor(LocalData data) {
1641 Intent intent = new Intent(Intent.ACTION_EDIT)
1642 .setDataAndType(data.getContentUri(), data.getMimeType())
1643 .setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
Erin Dahlgren05a04922013-11-07 11:35:10 -08001644 try {
1645 startActivityForResult(intent, REQ_CODE_DONT_SWITCH_TO_PREVIEW);
1646 } catch (ActivityNotFoundException e) {
1647 startActivityForResult(Intent.createChooser(intent, null),
1648 REQ_CODE_DONT_SWITCH_TO_PREVIEW);
1649 }
Sascha Haeberling88ef7662013-08-15 17:19:22 -07001650 }
1651
Sascha Haeberlinga5a08d72013-09-11 20:30:52 -07001652 /**
1653 * Launch the tiny planet editor.
1654 *
Angus Kong20fad242013-11-11 18:23:46 -08001655 * @param data The data must be a 360 degree stereographically mapped
1656 * panoramic image. It will not be modified, instead a new item
1657 * with the result will be added to the filmstrip.
Sascha Haeberlinga5a08d72013-09-11 20:30:52 -07001658 */
1659 public void launchTinyPlanetEditor(LocalData data) {
1660 TinyPlanetFragment fragment = new TinyPlanetFragment();
1661 Bundle bundle = new Bundle();
1662 bundle.putString(TinyPlanetFragment.ARGUMENT_URI, data.getContentUri().toString());
1663 bundle.putString(TinyPlanetFragment.ARGUMENT_TITLE, data.getTitle());
1664 fragment.setArguments(bundle);
1665 fragment.show(getFragmentManager(), "tiny_planet");
1666 }
1667
Doris Liu6432cd62013-06-13 17:20:31 -07001668 private void openModule(CameraModule module) {
Angus Kong13e87c42013-11-25 10:02:47 -08001669 module.init(this, isSecureCamera(), isCaptureIntent());
Angus Kongc4e66562013-11-22 23:03:21 -08001670 module.resume();
Doris Liu6432cd62013-06-13 17:20:31 -07001671 }
1672
1673 private void closeModule(CameraModule module) {
Angus Kongc4e66562013-11-22 23:03:21 -08001674 module.pause();
Angus Kong653c43b2013-08-21 18:28:43 -07001675 }
1676
Doris Liu742cd5b2013-09-12 16:17:43 -07001677 private void performDeletion() {
1678 if (!mPendingDeletion) {
1679 return;
1680 }
1681 hideUndoDeletionBar(false);
1682 mDataAdapter.executeDeletion(CameraActivity.this);
Erin Dahlgrenfd7f0a92013-10-21 10:08:54 -07001683
Angus Kong62848152013-11-08 17:25:29 -08001684 int currentId = mFilmstripController.getCurrentId();
Erin Dahlgrenfd7f0a92013-10-21 10:08:54 -07001685 updateActionBarMenu(currentId);
1686 mFilmStripListener.onCurrentDataCentered(currentId);
Doris Liu742cd5b2013-09-12 16:17:43 -07001687 }
1688
1689 public void showUndoDeletionBar() {
1690 if (mPendingDeletion) {
1691 performDeletion();
1692 }
1693 Log.v(TAG, "showing undo bar");
1694 mPendingDeletion = true;
Angus Kong653c43b2013-08-21 18:28:43 -07001695 if (mUndoDeletionBar == null) {
Angus Kong20fad242013-11-11 18:23:46 -08001696 ViewGroup v = (ViewGroup) getLayoutInflater().inflate(R.layout.undo_bar,
1697 mAboveFilmstripControlLayout, true);
Angus Kong653c43b2013-08-21 18:28:43 -07001698 mUndoDeletionBar = (ViewGroup) v.findViewById(R.id.camera_undo_deletion_bar);
1699 View button = mUndoDeletionBar.findViewById(R.id.camera_undo_deletion_button);
1700 button.setOnClickListener(new View.OnClickListener() {
1701 @Override
1702 public void onClick(View view) {
1703 mDataAdapter.undoDataRemoval();
Doris Liu742cd5b2013-09-12 16:17:43 -07001704 hideUndoDeletionBar(true);
1705 }
1706 });
1707 // Setting undo bar clickable to avoid touch events going through
1708 // the bar to the buttons (eg. edit button, etc) underneath the bar.
1709 mUndoDeletionBar.setClickable(true);
1710 // When there is user interaction going on with the undo button, we
1711 // do not want to hide the undo bar.
1712 button.setOnTouchListener(new View.OnTouchListener() {
1713 @Override
1714 public boolean onTouch(View v, MotionEvent event) {
1715 if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
1716 mIsUndoingDeletion = true;
1717 } else if (event.getActionMasked() == MotionEvent.ACTION_UP) {
Angus Kong20fad242013-11-11 18:23:46 -08001718 mIsUndoingDeletion = false;
Doris Liu742cd5b2013-09-12 16:17:43 -07001719 }
1720 return false;
Angus Kong653c43b2013-08-21 18:28:43 -07001721 }
1722 });
1723 }
1724 mUndoDeletionBar.setAlpha(0f);
1725 mUndoDeletionBar.setVisibility(View.VISIBLE);
Doris Liu742cd5b2013-09-12 16:17:43 -07001726 mUndoDeletionBar.animate().setDuration(200).alpha(1f).setListener(null).start();
Angus Kong653c43b2013-08-21 18:28:43 -07001727 }
1728
Doris Liu742cd5b2013-09-12 16:17:43 -07001729 private void hideUndoDeletionBar(boolean withAnimation) {
Angus Kong653c43b2013-08-21 18:28:43 -07001730 Log.v(TAG, "Hiding undo deletion bar");
Doris Liu742cd5b2013-09-12 16:17:43 -07001731 mPendingDeletion = false;
Angus Kong653c43b2013-08-21 18:28:43 -07001732 if (mUndoDeletionBar != null) {
Doris Liu742cd5b2013-09-12 16:17:43 -07001733 if (withAnimation) {
Angus Kong20fad242013-11-11 18:23:46 -08001734 mUndoDeletionBar.animate().setDuration(200).alpha(0f)
Doris Liu742cd5b2013-09-12 16:17:43 -07001735 .setListener(new Animator.AnimatorListener() {
1736 @Override
1737 public void onAnimationStart(Animator animation) {
1738 // Do nothing.
1739 }
1740
1741 @Override
1742 public void onAnimationEnd(Animator animation) {
1743 mUndoDeletionBar.setVisibility(View.GONE);
1744 }
1745
1746 @Override
1747 public void onAnimationCancel(Animator animation) {
1748 // Do nothing.
1749 }
1750
1751 @Override
1752 public void onAnimationRepeat(Animator animation) {
1753 // Do nothing.
1754 }
Angus Kong20fad242013-11-11 18:23:46 -08001755 }).start();
Doris Liu742cd5b2013-09-12 16:17:43 -07001756 } else {
1757 mUndoDeletionBar.setVisibility(View.GONE);
1758 }
Angus Kong653c43b2013-08-21 18:28:43 -07001759 }
Michael Kolb8872c232013-01-29 10:33:22 -08001760 }
1761
1762 @Override
Angus Kong9f1db522013-11-09 16:25:59 -08001763 public void onOrientationChanged(int orientation) {
1764 // We keep the last known orientation. So if the user first orient
1765 // the camera then point the camera to floor or sky, we still have
1766 // the correct orientation.
1767 if (orientation == OrientationManager.ORIENTATION_UNKNOWN) {
1768 return;
1769 }
1770 mLastRawOrientation = orientation;
1771 if (mCurrentModule != null) {
1772 mCurrentModule.onOrientationChanged(orientation);
1773 }
1774 }
1775
Angus Konga7194602013-09-06 17:20:15 -07001776 /**
Sascha Haeberlinga5a08d72013-09-11 20:30:52 -07001777 * Enable/disable swipe-to-filmstrip. Will always disable swipe if in
1778 * capture intent.
Angus Konga7194602013-09-06 17:20:15 -07001779 *
1780 * @param enable {@code true} to enable swipe.
1781 */
Doris Liu6432cd62013-06-13 17:20:31 -07001782 public void setSwipingEnabled(boolean enable) {
Angus Konga7194602013-09-06 17:20:15 -07001783 if (isCaptureIntent()) {
1784 mCameraPreviewData.lockPreview(true);
1785 } else {
1786 mCameraPreviewData.lockPreview(!enable);
1787 }
Michael Kolb8872c232013-01-29 10:33:22 -08001788 }
1789
Erin Dahlgren3044d8c2013-10-10 18:23:45 -07001790
1791 /**
1792 * Check whether camera controls are visible.
1793 *
1794 * @return whether controls are visible.
1795 */
1796 private boolean arePreviewControlsVisible() {
1797 return mCurrentModule.arePreviewControlsVisible();
1798 }
1799
1800 /**
1801 * Show or hide the {@link CameraControls} using the current module's
1802 * implementation of {@link #onPreviewFocusChanged}.
1803 *
1804 * @param showControls whether to show camera controls.
1805 */
1806 private void setPreviewControlsVisibility(boolean showControls) {
1807 mCurrentModule.onPreviewFocusChanged(showControls);
1808 }
1809
Michael Kolb8872c232013-01-29 10:33:22 -08001810 // Accessor methods for getting latency times used in performance testing
1811 public long getAutoFocusTime() {
1812 return (mCurrentModule instanceof PhotoModule) ?
1813 ((PhotoModule) mCurrentModule).mAutoFocusTime : -1;
1814 }
1815
1816 public long getShutterLag() {
1817 return (mCurrentModule instanceof PhotoModule) ?
1818 ((PhotoModule) mCurrentModule).mShutterLag : -1;
1819 }
1820
1821 public long getShutterToPictureDisplayedTime() {
1822 return (mCurrentModule instanceof PhotoModule) ?
1823 ((PhotoModule) mCurrentModule).mShutterToPictureDisplayedTime : -1;
1824 }
1825
1826 public long getPictureDisplayedToJpegCallbackTime() {
1827 return (mCurrentModule instanceof PhotoModule) ?
1828 ((PhotoModule) mCurrentModule).mPictureDisplayedToJpegCallbackTime : -1;
1829 }
1830
1831 public long getJpegCallbackFinishTime() {
1832 return (mCurrentModule instanceof PhotoModule) ?
1833 ((PhotoModule) mCurrentModule).mJpegCallbackFinishTime : -1;
1834 }
1835
1836 public long getCaptureStartTime() {
1837 return (mCurrentModule instanceof PhotoModule) ?
1838 ((PhotoModule) mCurrentModule).mCaptureStartTime : -1;
1839 }
1840
1841 public boolean isRecording() {
1842 return (mCurrentModule instanceof VideoModule) ?
1843 ((VideoModule) mCurrentModule).isRecording() : false;
1844 }
Angus Kong4f795b82013-09-16 14:25:35 -07001845
Angus Kong62848152013-11-08 17:25:29 -08001846 public CameraManager.CameraOpenCallback getCameraOpenErrorCallback() {
Angus Kong20fad242013-11-11 18:23:46 -08001847 return mCameraController;
Angus Kong4f795b82013-09-16 14:25:35 -07001848 }
Ruben Brunkd217ed02013-10-08 23:31:13 -07001849
1850 // For debugging purposes only.
1851 public CameraModule getCurrentModule() {
1852 return mCurrentModule;
1853 }
Angus Kong13e87c42013-11-25 10:02:47 -08001854
1855 private void keepScreenOnForAWhile() {
1856 if (mKeepScreenOn) {
1857 return;
1858 }
1859 mMainHandler.removeMessages(MSG_CLEAR_SCREEN_ON_FLAG);
1860 getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
1861 mMainHandler.sendEmptyMessageDelayed(MSG_CLEAR_SCREEN_ON_FLAG, SCREEN_DELAY_MS);
1862 }
1863
1864 private void resetScreenOn() {
1865 mKeepScreenOn = false;
1866 mMainHandler.removeMessages(MSG_CLEAR_SCREEN_ON_FLAG);
1867 getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
1868 }
Michael Kolb8872c232013-01-29 10:33:22 -08001869}