blob: bd27f75d1081be451b43a603366430f56ea6bd2b [file] [log] [blame]
Michael Kolb8872c232013-01-29 10:33:22 -08001/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.camera;
18
Doris Liu742cd5b2013-09-12 16:17:43 -070019import android.animation.Animator;
Mangesh Ghiwarea5682ab2013-09-19 09:24:23 -070020import android.annotation.TargetApi;
ztenghuifa9e2cc2013-08-09 17:37:15 -070021import android.app.ActionBar;
Doris Liu6432cd62013-06-13 17:20:31 -070022import android.app.Activity;
Angus Kong01054e92013-12-10 11:06:18 -080023import android.app.AlertDialog;
Angus Kong26795a92014-02-20 09:18:09 -080024import android.app.Dialog;
Mangesh Ghiware30968d02013-10-02 14:38:12 -070025import android.content.ActivityNotFoundException;
Doris Liub84b9732013-06-18 17:14:26 -070026import android.content.BroadcastReceiver;
Doris Liu6432cd62013-06-13 17:20:31 -070027import android.content.ContentResolver;
Michael Kolb08650182013-02-25 19:43:56 -080028import android.content.Context;
Michael Kolb8872c232013-01-29 10:33:22 -080029import android.content.Intent;
Doris Liub84b9732013-06-18 17:14:26 -070030import android.content.IntentFilter;
Doris Liu3cf565c2013-02-15 10:55:37 -080031import android.content.pm.ActivityInfo;
Angus Kong6c0c7f12014-01-15 14:40:27 -080032import android.content.pm.PackageManager;
Michael Kolb8872c232013-01-29 10:33:22 -080033import android.content.res.Configuration;
Angus Kong9f1db522013-11-09 16:25:59 -080034import android.graphics.Bitmap;
Angus Kong571a8c32014-03-13 12:53:03 -070035import android.graphics.BitmapFactory;
Doris Liu70da9182013-12-17 18:41:15 -080036import android.graphics.Matrix;
Angus Kongc195e7a2014-02-20 16:56:37 -080037import android.graphics.Point;
Angus Kong9f1db522013-11-09 16:25:59 -080038import android.graphics.SurfaceTexture;
Doris Liu6432cd62013-06-13 17:20:31 -070039import android.graphics.drawable.ColorDrawable;
Angus Kong6c0c7f12014-01-15 14:40:27 -080040import android.graphics.drawable.Drawable;
Spike Spragueabf54e22014-03-27 15:41:28 -070041import android.hardware.Camera;
Doris Liu6432cd62013-06-13 17:20:31 -070042import android.net.Uri;
Mangesh Ghiwarea5682ab2013-09-19 09:24:23 -070043import android.nfc.NfcAdapter;
44import android.nfc.NfcAdapter.CreateBeamUrisCallback;
45import android.nfc.NfcEvent;
Sam Juddde3e9ab2014-03-17 13:07:22 -070046import android.os.AsyncTask;
Mangesh Ghiwarea5682ab2013-09-19 09:24:23 -070047import android.os.Build;
Michael Kolb8872c232013-01-29 10:33:22 -080048import android.os.Bundle;
Doris Liu6432cd62013-06-13 17:20:31 -070049import android.os.Handler;
Angus Kong50521172014-01-17 17:23:59 -080050import android.os.HandlerThread;
Doris Liuaa874422013-09-18 19:43:12 -070051import android.os.Looper;
52import android.os.Message;
Doris Liu2a7f44c2013-08-12 15:18:53 -070053import android.provider.MediaStore;
Doris Liu3cf565c2013-02-15 10:55:37 -080054import android.provider.Settings;
Doris Liu7cbecee2014-01-30 12:29:27 -080055import android.util.CameraPerformanceTracker;
Sascha Haeberlinge8959e72014-01-31 15:21:02 +010056import android.view.ContextMenu;
57import android.view.ContextMenu.ContextMenuInfo;
Michael Kolb8872c232013-01-29 10:33:22 -080058import android.view.KeyEvent;
Sascha Haeberlingd114a772014-02-28 21:27:27 -080059import android.view.Menu;
Sascha Haeberlinge8959e72014-01-31 15:21:02 +010060import android.view.MenuInflater;
ztenghui0353ca22013-08-13 13:53:16 -070061import android.view.MenuItem;
Doris Liu742cd5b2013-09-12 16:17:43 -070062import android.view.MotionEvent;
Michael Kolb8872c232013-01-29 10:33:22 -080063import android.view.View;
Sascha Haeberling099b49b2014-04-08 07:08:46 -070064import android.view.View.OnSystemUiVisibilityChangeListener;
Doris Liu6432cd62013-06-13 17:20:31 -070065import android.view.ViewGroup;
Michael Kolb08650182013-02-25 19:43:56 -080066import android.view.Window;
67import android.view.WindowManager;
Angus Kong653c43b2013-08-21 18:28:43 -070068import android.widget.FrameLayout;
Doris Liu6432cd62013-06-13 17:20:31 -070069import android.widget.ImageView;
Mangesh Ghiwarecd2eeb02013-08-23 13:28:21 -070070import android.widget.ShareActionProvider;
Michael Kolb8872c232013-01-29 10:33:22 -080071
Angus Kong9f1db522013-11-09 16:25:59 -080072import com.android.camera.app.AppController;
Doris Liuf55f3c42013-11-20 00:24:46 -080073import com.android.camera.app.CameraAppUI;
Angus Kong20fad242013-11-11 18:23:46 -080074import com.android.camera.app.CameraController;
75import com.android.camera.app.CameraManager;
76import com.android.camera.app.CameraManagerFactory;
77import com.android.camera.app.CameraProvider;
Angus Kongc4e66562013-11-22 23:03:21 -080078import com.android.camera.app.CameraServices;
Kevin Gabayanffbc43c2013-12-09 11:41:50 -080079import com.android.camera.app.LocationManager;
Kevin Gabayan0aeb0c82014-04-08 11:12:05 -070080import com.android.camera.app.MemoryManager;
Kevin Gabayan05ee74d2014-04-08 16:25:23 -070081import com.android.camera.app.MemoryQuery;
Angus Kong20fad242013-11-11 18:23:46 -080082import com.android.camera.app.ModuleManagerImpl;
Angus Kong9f1db522013-11-09 16:25:59 -080083import com.android.camera.app.OrientationManager;
84import com.android.camera.app.OrientationManagerImpl;
Doris Liu6432cd62013-06-13 17:20:31 -070085import com.android.camera.data.CameraDataAdapter;
Angus Kong8e5e4ee2013-07-30 11:36:00 -070086import com.android.camera.data.FixedLastDataAdapter;
Doris Liu6432cd62013-06-13 17:20:31 -070087import com.android.camera.data.LocalData;
Angus Kong8e5e4ee2013-07-30 11:36:00 -070088import com.android.camera.data.LocalDataAdapter;
Angus Kong50521172014-01-17 17:23:59 -080089import com.android.camera.data.LocalDataUtil;
Angus Kong571a8c32014-03-13 12:53:03 -070090import com.android.camera.data.LocalMediaData;
ztenghui064d6002013-09-05 15:47:58 -070091import com.android.camera.data.LocalMediaObserver;
Angus Kong571a8c32014-03-13 12:53:03 -070092import com.android.camera.data.LocalSessionData;
Angus Kong26795a92014-02-20 09:18:09 -080093import com.android.camera.data.MediaDetails;
Angus Kong8a2350a2013-12-16 15:02:34 -080094import com.android.camera.data.PanoramaMetadataLoader;
95import com.android.camera.data.RgbzMetadataLoader;
Angus Kongbd260692013-08-07 14:52:56 -070096import com.android.camera.data.SimpleViewData;
Angus Kong5596b4c2014-03-11 16:27:30 -070097import com.android.camera.debug.Log;
Angus Kong01054e92013-12-10 11:06:18 -080098import com.android.camera.filmstrip.FilmstripContentPanel;
Angus Kong62848152013-11-08 17:25:29 -080099import com.android.camera.filmstrip.FilmstripController;
Erin Dahlgrene346fb22014-02-19 17:23:01 -0800100import com.android.camera.hardware.HardwareSpec;
101import com.android.camera.hardware.HardwareSpecImpl;
Erin Dahlgren0a6a8d82014-01-09 22:17:38 -0800102import com.android.camera.module.ModuleController;
Angus Kong612321f2013-11-18 16:17:43 -0800103import com.android.camera.module.ModulesInfo;
Seth Raphael16bca012014-03-21 09:56:11 -0700104import com.android.camera.session.CaptureSession;
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800105import com.android.camera.session.CaptureSessionManager;
106import com.android.camera.session.CaptureSessionManager.SessionListener;
Sascha Haeberlingde303232014-02-07 02:30:53 +0100107import com.android.camera.settings.CameraSettingsActivity;
Erin Dahlgren357b7672013-11-20 17:38:14 -0800108import com.android.camera.settings.SettingsManager;
109import com.android.camera.settings.SettingsManager.SettingsCapabilities;
Sascha Haeberlingde303232014-02-07 02:30:53 +0100110import com.android.camera.settings.SettingsUtil;
Sascha Haeberlinga5a08d72013-09-11 20:30:52 -0700111import com.android.camera.tinyplanet.TinyPlanetFragment;
Sascha Haeberlingc813ce12014-03-10 15:35:07 -0700112import com.android.camera.ui.AbstractTutorialOverlay;
Angus Kong26795a92014-02-20 09:18:09 -0800113import com.android.camera.ui.DetailsDialog;
Doris Liuf55f3c42013-11-20 00:24:46 -0800114import com.android.camera.ui.MainActivityLayout;
Doris Liu1c94b7d2013-11-09 19:13:44 -0800115import com.android.camera.ui.ModeListView;
Sascha Haeberling8c1a9222014-02-25 09:38:06 -0800116import com.android.camera.ui.ModeListView.ModeListVisibilityChangedListener;
Doris Liu06db7422013-12-09 19:36:25 -0800117import com.android.camera.ui.PreviewStatusListener;
Sascha Haeberling88ef7662013-08-15 17:19:22 -0700118import com.android.camera.util.ApiHelper;
Sascha Haeberlingde303232014-02-07 02:30:53 +0100119import com.android.camera.util.Callback;
Angus Kongb50b5cb2013-08-09 14:55:20 -0700120import com.android.camera.util.CameraUtil;
Christian Wyglendowski6fe8c822013-11-26 14:16:04 -0800121import com.android.camera.util.FeedbackHelper;
Alan Newberger80461c22014-02-03 15:03:26 -0800122import com.android.camera.util.GalleryHelper;
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700123import com.android.camera.util.GcamHelper;
Alan Newberger761306f2013-10-30 12:51:21 -0700124import com.android.camera.util.IntentHelper;
Sascha Haeberling88ef7662013-08-15 17:19:22 -0700125import com.android.camera.util.PhotoSphereHelper.PanoramaViewHelper;
Sascha Haeberlingc26a3282014-02-19 08:39:28 -0800126import com.android.camera.util.ReleaseDialogHelper;
Seth Raphaelcbd82672013-11-05 10:12:36 -0800127import com.android.camera.util.UsageStatistics;
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800128import com.android.camera.widget.FilmstripView;
Sam Juddde3e9ab2014-03-17 13:07:22 -0700129import com.android.camera.widget.Preloader;
Sascha Haeberling8e963a52013-08-06 11:43:02 -0700130import com.android.camera2.R;
Seth Raphael5e09d012013-12-18 13:45:03 -0800131import com.google.common.logging.eventprotos;
Andy Huibers10c58162014-03-29 14:06:54 -0700132import com.google.common.logging.eventprotos.ForegroundEvent.ForegroundSource;
Sascha Haeberling099b49b2014-04-08 07:08:46 -0700133import com.google.common.logging.eventprotos.MediaInteraction;
134import com.google.common.logging.eventprotos.NavigationChange;
Michael Kolb8872c232013-01-29 10:33:22 -0800135
Seth Raphaelcbd82672013-11-05 10:12:36 -0800136import java.io.File;
Angus Kong50521172014-01-17 17:23:59 -0800137import java.io.FileInputStream;
138import java.io.FileNotFoundException;
Sascha Haeberling846d3ab2014-02-04 12:48:55 +0100139import java.lang.ref.WeakReference;
Erin Dahlgrenf63967a2014-01-02 13:57:43 -0800140import java.util.ArrayList;
Kevin Gabayan0aeb0c82014-04-08 11:12:05 -0700141import java.util.HashMap;
Sascha Haeberling8793eff2014-01-15 16:33:59 -0800142import java.util.List;
Seth Raphaelcbd82672013-11-05 10:12:36 -0800143
Doris Liu6432cd62013-06-13 17:20:31 -0700144public class CameraActivity extends Activity
Doris Liuf55f3c42013-11-20 00:24:46 -0800145 implements AppController, CameraManager.CameraOpenCallback,
Angus Kong9f1db522013-11-09 16:25:59 -0800146 ActionBar.OnMenuVisibilityListener, ShareActionProvider.OnShareTargetSelectedListener,
147 OrientationManager.OnOrientationChangeListener {
Doris Liu6432cd62013-06-13 17:20:31 -0700148
Angus Kong5596b4c2014-03-11 16:27:30 -0700149 private static final Log.Tag TAG = new Log.Tag("CameraActivity");
Doris Liu6432cd62013-06-13 17:20:31 -0700150
Doris Liu6432cd62013-06-13 17:20:31 -0700151 private static final String INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE =
152 "android.media.action.STILL_IMAGE_CAMERA_SECURE";
153 public static final String ACTION_IMAGE_CAPTURE_SECURE =
154 "android.media.action.IMAGE_CAPTURE_SECURE";
155
156 // The intent extra for camera from secure lock screen. True if the gallery
157 // should only show newly captured pictures. sSecureAlbumId does not
158 // increment. This is used when switching between camera, camcorder, and
159 // panorama. If the extra is not set, it is in the normal camera mode.
160 public static final String SECURE_CAMERA_EXTRA = "secure_camera";
161
Sascha Haeberlingb7639c62013-09-09 14:42:43 -0700162 /**
Sascha Haeberling846d3ab2014-02-04 12:48:55 +0100163 * Request code from an activity we started that indicated that we do not
164 * want to reset the view to the preview in onResume.
Sascha Haeberlingb7639c62013-09-09 14:42:43 -0700165 */
166 public static final int REQ_CODE_DONT_SWITCH_TO_PREVIEW = 142;
167
Ruben Brunkd217ed02013-10-08 23:31:13 -0700168 public static final int REQ_CODE_GCAM_DEBUG_POSTCAPTURE = 999;
169
Angus Kong13e87c42013-11-25 10:02:47 -0800170 private static final int MSG_CLEAR_SCREEN_ON_FLAG = 2;
Sascha Haeberling846d3ab2014-02-04 12:48:55 +0100171 private static final long SCREEN_DELAY_MS = 2 * 60 * 1000; // 2 mins.
Angus Kong50521172014-01-17 17:23:59 -0800172 private static final int MAX_PEEK_BITMAP_PIXELS = 1600000; // 1.6 * 4 MBs.
Sam Juddde3e9ab2014-03-17 13:07:22 -0700173 /** Load metadata for 10 items ahead of our current. */
174 private static final int FILMSTRIP_PRELOAD_AHEAD_ITEMS = 10;
Sascha Haeberling846d3ab2014-02-04 12:48:55 +0100175
176 /** Should be used wherever a context is needed. */
177 private Context mAppContext;
Doris Liuaa874422013-09-18 19:43:12 -0700178
Angus Kong20fad242013-11-11 18:23:46 -0800179 /**
180 * Whether onResume should reset the view to the preview.
181 */
Sascha Haeberlingb7639c62013-09-09 14:42:43 -0700182 private boolean mResetToPreviewOnResume = true;
183
Angus Kong20fad242013-11-11 18:23:46 -0800184 /**
185 * This data adapter is used by FilmStripView.
186 */
Angus Kong8e5e4ee2013-07-30 11:36:00 -0700187 private LocalDataAdapter mDataAdapter;
Angus Kong8e5e4ee2013-07-30 11:36:00 -0700188
Erin Dahlgrenc120b0f2013-11-19 10:53:49 -0800189 private SettingsManager mSettingsManager;
Doris Liu70576b62013-11-14 20:30:33 -0800190 private ModeListView mModeListView;
Sascha Haeberling2d11fcf2014-03-13 09:04:32 -0700191 private boolean mModeListVisible = false;
Erin Dahlgrenc120b0f2013-11-19 10:53:49 -0800192 private int mCurrentModeIndex;
Doris Liu6432cd62013-06-13 17:20:31 -0700193 private CameraModule mCurrentModule;
Angus Kong20fad242013-11-11 18:23:46 -0800194 private ModuleManagerImpl mModuleManager;
Angus Kong653c43b2013-08-21 18:28:43 -0700195 private FrameLayout mAboveFilmstripControlLayout;
Angus Kong62848152013-11-08 17:25:29 -0800196 private FilmstripController mFilmstripController;
Angus Kongfaaee012013-12-07 00:38:46 -0800197 private boolean mFilmstripVisible;
Sascha Haeberling2d11fcf2014-03-13 09:04:32 -0700198 /** Whether the filmstrip fully covers the preview. */
199 private boolean mFilmstripCoversPreview = false;
Doris Liu6432cd62013-06-13 17:20:31 -0700200 private int mResultCodeForTesting;
201 private Intent mResultDataForTesting;
202 private OnScreenHint mStorageHint;
Sascha Haeberlinge3e270f2014-04-02 23:27:50 -0700203 private final Object mStorageSpaceLock = new Object();
Angus Kong2dcc0a92013-09-25 13:00:08 -0700204 private long mStorageSpaceBytes = Storage.LOW_STORAGE_THRESHOLD_BYTES;
Doris Liu3cf565c2013-02-15 10:55:37 -0800205 private boolean mAutoRotateScreen;
Doris Liu6432cd62013-06-13 17:20:31 -0700206 private boolean mSecureCamera;
Doris Liu6432cd62013-06-13 17:20:31 -0700207 private int mLastRawOrientation;
Angus Kong9f1db522013-11-09 16:25:59 -0800208 private OrientationManagerImpl mOrientationManager;
Erin Dahlgren21c21a62013-11-19 16:37:38 -0800209 private LocationManager mLocationManager;
Erin Dahlgren8a2933b2013-12-06 12:07:33 -0800210 private ButtonManager mButtonManager;
Doris Liu6432cd62013-06-13 17:20:31 -0700211 private Handler mMainHandler;
Sascha Haeberlingf1f51862013-07-31 11:28:21 -0700212 private PanoramaViewHelper mPanoramaViewHelper;
ztenghuifa9e2cc2013-08-09 17:37:15 -0700213 private ActionBar mActionBar;
Angus Kong653c43b2013-08-21 18:28:43 -0700214 private ViewGroup mUndoDeletionBar;
Doris Liu742cd5b2013-09-12 16:17:43 -0700215 private boolean mIsUndoingDeletion = false;
Doris Liu3cf565c2013-02-15 10:55:37 -0800216
Sascha Haeberling280fd3e2013-11-21 13:52:15 -0800217 private final Uri[] mNfcPushUris = new Uri[1];
Mangesh Ghiwarea5682ab2013-09-19 09:24:23 -0700218
ztenghui064d6002013-09-05 15:47:58 -0700219 private LocalMediaObserver mLocalImagesObserver;
220 private LocalMediaObserver mLocalVideosObserver;
Mangesh Ghiwarecd2eeb02013-08-23 13:28:21 -0700221
Doris Liu742cd5b2013-09-12 16:17:43 -0700222 private boolean mPendingDeletion = false;
Sascha Haeberling5199c202013-09-05 17:10:19 -0700223
Angus Kong20fad242013-11-11 18:23:46 -0800224 private CameraController mCameraController;
Erin Dahlgrenc120b0f2013-11-19 10:53:49 -0800225 private boolean mPaused;
Doris Liuf55f3c42013-11-20 00:24:46 -0800226 private CameraAppUI mCameraAppUI;
Angus Kong20fad242013-11-11 18:23:46 -0800227
Angus Kong50521172014-01-17 17:23:59 -0800228 private PeekAnimationHandler mPeekAnimationHandler;
229 private HandlerThread mPeekAnimationThread;
230
Christian Wyglendowski6fe8c822013-11-26 14:16:04 -0800231 private FeedbackHelper mFeedbackHelper;
Kevin Gabayana0e83472014-01-15 15:21:13 -0800232
Angus Kong6c0c7f12014-01-15 14:40:27 -0800233 private Intent mGalleryIntent;
Kevin Gabayana0e83472014-01-15 15:21:13 -0800234 private long mOnCreateTime;
Christian Wyglendowski6fe8c822013-11-26 14:16:04 -0800235
Sascha Haeberlingd114a772014-02-28 21:27:27 -0800236 private Menu mActionBarMenu;
Sam Juddde3e9ab2014-03-17 13:07:22 -0700237 private Preloader<Integer, AsyncTask> mPreloader;
Sascha Haeberlingd114a772014-02-28 21:27:27 -0800238
Sascha Haeberling099b49b2014-04-08 07:08:46 -0700239 private static final int LIGHTS_OUT_DELAY_MS = 4000;
240 private final int BASE_SYS_UI_VISIBILITY = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
241 | View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
242 private final Runnable mLightsOutRunnable = new Runnable() {
243 @Override
244 public void run() {
245 getWindow().getDecorView().setSystemUiVisibility(
246 BASE_SYS_UI_VISIBILITY | View.SYSTEM_UI_FLAG_LOW_PROFILE);
247 }
248 };
Kevin Gabayan0aeb0c82014-04-08 11:12:05 -0700249 private MemoryManager mMemoryManager;
Sascha Haeberling099b49b2014-04-08 07:08:46 -0700250
Spike Sprague0f3c4b42013-12-10 19:50:17 -0800251 @Override
252 public CameraAppUI getCameraAppUI() {
253 return mCameraAppUI;
254 }
255
Doris Liub84b9732013-06-18 17:14:26 -0700256 // close activity when screen turns off
Sascha Haeberling280fd3e2013-11-21 13:52:15 -0800257 private final BroadcastReceiver mScreenOffReceiver = new BroadcastReceiver() {
Doris Liub84b9732013-06-18 17:14:26 -0700258 @Override
259 public void onReceive(Context context, Intent intent) {
260 finish();
261 }
262 };
263
Angus Kong13e87c42013-11-25 10:02:47 -0800264 /**
265 * Whether the screen is kept turned on.
266 */
267 private boolean mKeepScreenOn;
Angus Kong53ae0412013-12-01 23:21:49 -0800268 private int mLastLayoutOrientation;
Angus Kong7ae25c22014-02-25 10:37:39 -0800269 private final CameraAppUI.BottomPanel.Listener mMyFilmstripBottomControlListener =
270 new CameraAppUI.BottomPanel.Listener() {
Angus Kongb2510252013-12-10 22:58:15 -0800271
272 /**
Sascha Haeberling846d3ab2014-02-04 12:48:55 +0100273 * If the current photo is a photo sphere, this will launch the
274 * Photo Sphere panorama viewer.
Angus Kongb2510252013-12-10 22:58:15 -0800275 */
276 @Override
Angus Kong8a2350a2013-12-16 15:02:34 -0800277 public void onExternalViewer() {
278 if (mPanoramaViewHelper == null) {
279 return;
280 }
281 final LocalData data = getCurrentLocalData();
282 if (data == null) {
283 return;
284 }
Angus Kong571a8c32014-03-13 12:53:03 -0700285 final Uri contentUri = data.getUri();
Angus Kong8a2350a2013-12-16 15:02:34 -0800286 if (contentUri == Uri.EMPTY) {
287 return;
288 }
289
Sascha Haeberling7190c6a2014-02-21 10:11:31 -0800290 if (PanoramaMetadataLoader.isPanoramaAndUseViewer(data)) {
Erin Dahlgren013ad4e2014-02-26 10:48:08 -0800291 mPanoramaViewHelper.showPanorama(CameraActivity.this, contentUri);
Angus Kong8a2350a2013-12-16 15:02:34 -0800292 } else if (RgbzMetadataLoader.hasRGBZData(data)) {
293 mPanoramaViewHelper.showRgbz(contentUri);
Doris Liue7d7b9e2014-03-31 15:27:40 -0700294 if (mSettingsManager.getBoolean(
295 SettingsManager.SETTING_SHOULD_SHOW_REFOCUS_VIEWER_CLING)) {
296 mSettingsManager.setBoolean(
297 SettingsManager.SETTING_SHOULD_SHOW_REFOCUS_VIEWER_CLING,
298 false);
299 mCameraAppUI.clearClingForViewer(
300 CameraAppUI.BottomPanel.VIEWER_REFOCUS);
301 }
Angus Kongb2510252013-12-10 22:58:15 -0800302 }
303 }
304
305 @Override
306 public void onEdit() {
307 LocalData data = getCurrentLocalData();
308 if (data == null) {
309 return;
310 }
Andy Huibers10c58162014-03-29 14:06:54 -0700311 final int currentDataId = getCurrentDataId();
312 UsageStatistics.instance().mediaInteraction(fileNameFromDataID(currentDataId),
313 MediaInteraction.InteractionType.EDIT,
314 NavigationChange.InteractionCause.BUTTON);
Angus Kongb2510252013-12-10 22:58:15 -0800315 launchEditor(data);
316 }
317
318 @Override
319 public void onTinyPlanet() {
320 LocalData data = getCurrentLocalData();
321 if (data == null) {
322 return;
323 }
324 launchTinyPlanetEditor(data);
325 }
326
Angus Konge0aff892013-12-11 20:51:01 -0800327 @Override
328 public void onDelete() {
329 final int currentDataId = getCurrentDataId();
Andy Huibers10c58162014-03-29 14:06:54 -0700330 UsageStatistics.instance().mediaInteraction(fileNameFromDataID(currentDataId),
331 MediaInteraction.InteractionType.DELETE,
332 NavigationChange.InteractionCause.BUTTON);
Angus Konge0aff892013-12-11 20:51:01 -0800333 removeData(currentDataId);
334 }
335
336 @Override
337 public void onShare() {
Angus Kong662fbf42013-12-12 13:22:03 -0800338 final LocalData data = getCurrentLocalData();
Andy Huibers10c58162014-03-29 14:06:54 -0700339 final int currentDataId = getCurrentDataId();
340 UsageStatistics.instance().mediaInteraction(fileNameFromDataID(currentDataId),
341 MediaInteraction.InteractionType.SHARE,
342 NavigationChange.InteractionCause.BUTTON);
Sascha Haeberling7190c6a2014-02-21 10:11:31 -0800343 // If applicable, show release information before this item
344 // is shared.
345 if (PanoramaMetadataLoader.isPanorama(data)
346 || RgbzMetadataLoader.hasRGBZData(data)) {
347 ReleaseDialogHelper.showReleaseInfoDialog(CameraActivity.this,
348 new Callback<Void>() {
349 @Override
350 public void onCallback(Void result) {
351 share(data);
352 }
353 });
354 } else {
355 share(data);
356 }
357 }
358
359 private void share(LocalData data) {
Angus Kong662fbf42013-12-12 13:22:03 -0800360 Intent shareIntent = getShareIntentByData(data);
361 if (shareIntent != null) {
Angus Konge4002f32013-12-13 22:24:11 -0800362 try {
Angus Kong0eaf0162013-12-16 15:53:30 -0800363 launchActivityByIntent(shareIntent);
Angus Konge4002f32013-12-13 22:24:11 -0800364 mCameraAppUI.getFilmstripBottomControls().setShareEnabled(false);
365 } catch (ActivityNotFoundException ex) {
366 // Nothing.
367 }
Angus Kong662fbf42013-12-12 13:22:03 -0800368 }
Angus Konge0aff892013-12-11 20:51:01 -0800369 }
370
Angus Konge0aff892013-12-11 20:51:01 -0800371 private int getCurrentDataId() {
372 return mFilmstripController.getCurrentId();
373 }
374
Angus Kongb2510252013-12-10 22:58:15 -0800375 private LocalData getCurrentLocalData() {
Angus Konge0aff892013-12-11 20:51:01 -0800376 return mDataAdapter.getLocalData(getCurrentDataId());
Angus Kongb2510252013-12-10 22:58:15 -0800377 }
Angus Kong662fbf42013-12-12 13:22:03 -0800378
379 /**
Sascha Haeberling846d3ab2014-02-04 12:48:55 +0100380 * Sets up the share intent and NFC properly according to the
381 * data.
Angus Kong662fbf42013-12-12 13:22:03 -0800382 *
383 * @param data The data to be shared.
384 */
385 private Intent getShareIntentByData(final LocalData data) {
386 Intent intent = null;
Angus Kong571a8c32014-03-13 12:53:03 -0700387 final Uri contentUri = data.getUri();
Angus Kong8a2350a2013-12-16 15:02:34 -0800388 if (PanoramaMetadataLoader.isPanorama360(data) &&
Angus Kong571a8c32014-03-13 12:53:03 -0700389 data.getUri() != Uri.EMPTY) {
Angus Kong662fbf42013-12-12 13:22:03 -0800390 intent = new Intent(Intent.ACTION_SEND);
391 intent.setType("application/vnd.google.panorama360+jpg");
392 intent.putExtra(Intent.EXTRA_STREAM, contentUri);
393 } else if (data.isDataActionSupported(LocalData.DATA_ACTION_SHARE)) {
394 final String mimeType = data.getMimeType();
395 intent = getShareIntentFromType(mimeType);
396 if (intent != null) {
397 intent.putExtra(Intent.EXTRA_STREAM, contentUri);
398 intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
399 }
Alan Newberger50c9cdc2014-02-28 16:50:19 -0800400 intent = Intent.createChooser(intent, null);
Angus Kong662fbf42013-12-12 13:22:03 -0800401 }
402 return intent;
403 }
404
405 /**
406 * Get the share intent according to the mimeType
407 *
408 * @param mimeType The mimeType of current data.
Sascha Haeberling846d3ab2014-02-04 12:48:55 +0100409 * @return the video/image's ShareIntent or null if mimeType is
410 * invalid.
Angus Kong662fbf42013-12-12 13:22:03 -0800411 */
412 private Intent getShareIntentFromType(String mimeType) {
413 // Lazily create the intent object.
414 Intent intent = new Intent(Intent.ACTION_SEND);
415 if (mimeType.startsWith("video/")) {
416 intent.setType("video/*");
417 } else {
418 if (mimeType.startsWith("image/")) {
419 intent.setType("image/*");
420 } else {
421 Log.w(TAG, "unsupported mimeType " + mimeType);
422 }
423 }
424 return intent;
425 }
Sascha Haeberling597c1a02014-03-06 11:46:06 -0800426
427 @Override
428 public void onProgressErrorClicked() {
429 LocalData data = getCurrentLocalData();
430 getServices().getCaptureSessionManager().removeErrorMessage(
Angus Kong571a8c32014-03-13 12:53:03 -0700431 data.getUri());
Sascha Haeberling597c1a02014-03-06 11:46:06 -0800432 updateBottomControlsByData(data);
433 }
Angus Kongb2510252013-12-10 22:58:15 -0800434 };
Angus Kong13e87c42013-11-25 10:02:47 -0800435
Angus Kong20fad242013-11-11 18:23:46 -0800436 @Override
437 public void onCameraOpened(CameraManager.CameraProxy camera) {
Erin Dahlgrene346fb22014-02-19 17:23:01 -0800438 /**
439 * The current UI requires that the flash option visibility in front-facing
440 * camera be
441 * * disabled if back facing camera supports flash
442 * * hidden if back facing camera does not support flash
443 * We save whether back facing camera supports flash because we cannot get
444 * this in front facing camera without a camera switch.
445 *
446 * If this preference is cleared, we also need to clear the camera facing
447 * setting so we default to opening the camera in back facing camera, and
448 * can save this flash support value again.
449 */
450 if (!mSettingsManager.isSet(SettingsManager.SETTING_FLASH_SUPPORTED_BACK_CAMERA)) {
451 HardwareSpec hardware = new HardwareSpecImpl(camera.getParameters());
452 mSettingsManager.setBoolean(SettingsManager.SETTING_FLASH_SUPPORTED_BACK_CAMERA,
453 hardware.isFlashSupported());
454 }
455
Erin Dahlgrenc120b0f2013-11-19 10:53:49 -0800456 if (!mModuleManager.getModuleAgent(mCurrentModeIndex).requestAppForCamera()) {
Angus Kong20fad242013-11-11 18:23:46 -0800457 // We shouldn't be here. Just close the camera and leave.
458 camera.release(false);
459 throw new IllegalStateException("Camera opened but the module shouldn't be " +
460 "requesting");
461 }
Angus Kong13e87c42013-11-25 10:02:47 -0800462 if (mCurrentModule != null) {
Erin Dahlgren357b7672013-11-20 17:38:14 -0800463 SettingsCapabilities capabilities =
Sascha Haeberlingde303232014-02-07 02:30:53 +0100464 SettingsUtil.getSettingsCapabilities(camera);
Erin Dahlgren357b7672013-11-20 17:38:14 -0800465 mSettingsManager.changeCamera(camera.getCameraId(), capabilities);
Spike Spragueabf54e22014-03-27 15:41:28 -0700466 resetExposureCompensationToDefault(camera);
Angus Kong13e87c42013-11-25 10:02:47 -0800467 mCurrentModule.onCameraAvailable(camera);
Angus Kong20fad242013-11-11 18:23:46 -0800468 }
Erin Dahlgren1648c362014-01-06 15:06:04 -0800469 mCameraAppUI.onChangeCamera();
Angus Kong20fad242013-11-11 18:23:46 -0800470 }
471
Spike Spragueabf54e22014-03-27 15:41:28 -0700472 private void resetExposureCompensationToDefault(CameraManager.CameraProxy camera) {
473 // Reset the exposure compensation before handing the camera to module.
474 Camera.Parameters parameters = camera.getParameters();
475 parameters.setExposureCompensation(0);
476 camera.setParameters(parameters);
477 }
478
Angus Kong20fad242013-11-11 18:23:46 -0800479 @Override
480 public void onCameraDisabled(int cameraId) {
Sascha Haeberlinga83ec8a2014-03-31 13:22:17 -0700481 UsageStatistics.instance().cameraFailure(
Andy Huiberseaaf2932014-04-28 13:18:31 -0700482 eventprotos.CameraFailure.FailureReason.SECURITY, null);
Andy Huibers10c58162014-03-29 14:06:54 -0700483 CameraUtil.showErrorAndFinish(this,
484 R.string.camera_disabled);
Angus Kong20fad242013-11-11 18:23:46 -0800485 }
486
487 @Override
Angus Kong1b9d4fb2014-04-25 11:41:23 -0700488 public void onDeviceOpenFailure(int cameraId, String info) {
Sascha Haeberlinga83ec8a2014-03-31 13:22:17 -0700489 UsageStatistics.instance().cameraFailure(
Andy Huiberseaaf2932014-04-28 13:18:31 -0700490 eventprotos.CameraFailure.FailureReason.OPEN_FAILURE, info);
Angus Kong20fad242013-11-11 18:23:46 -0800491 CameraUtil.showErrorAndFinish(this, R.string.cannot_connect_camera);
492 }
493
494 @Override
Angus Kong62753ae2014-02-10 10:53:54 -0800495 public void onDeviceOpenedAlready(int cameraId) {
496 CameraUtil.showErrorAndFinish(this, R.string.cannot_connect_camera);
497 }
498
499 @Override
Angus Kong20fad242013-11-11 18:23:46 -0800500 public void onReconnectionFailure(CameraManager mgr) {
Sascha Haeberlinga83ec8a2014-03-31 13:22:17 -0700501 UsageStatistics.instance().cameraFailure(
Andy Huiberseaaf2932014-04-28 13:18:31 -0700502 eventprotos.CameraFailure.FailureReason.RECONNECT_FAILURE, null);
Angus Kong20fad242013-11-11 18:23:46 -0800503 CameraUtil.showErrorAndFinish(this, R.string.cannot_connect_camera);
504 }
505
Sascha Haeberling846d3ab2014-02-04 12:48:55 +0100506 private static class MainHandler extends Handler {
507 final WeakReference<CameraActivity> mActivity;
Sascha Haeberlingde303232014-02-07 02:30:53 +0100508
Sascha Haeberling846d3ab2014-02-04 12:48:55 +0100509 public MainHandler(CameraActivity activity, Looper looper) {
Doris Liuaa874422013-09-18 19:43:12 -0700510 super(looper);
Sascha Haeberling846d3ab2014-02-04 12:48:55 +0100511 mActivity = new WeakReference<CameraActivity>(activity);
Doris Liuaa874422013-09-18 19:43:12 -0700512 }
513
514 @Override
515 public void handleMessage(Message msg) {
Sascha Haeberling846d3ab2014-02-04 12:48:55 +0100516 CameraActivity activity = mActivity.get();
517 if (activity == null) {
518 return;
519 }
Angus Kong13e87c42013-11-25 10:02:47 -0800520 switch (msg.what) {
Angus Kong13e87c42013-11-25 10:02:47 -0800521
Sascha Haeberling846d3ab2014-02-04 12:48:55 +0100522 case MSG_CLEAR_SCREEN_ON_FLAG: {
Sascha Haeberlingaa46ec92014-02-05 21:48:55 +0100523 if (!activity.mPaused) {
524 activity.getWindow().clearFlags(
525 WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
Angus Kong13e87c42013-11-25 10:02:47 -0800526 }
527 break;
528 }
Doris Liuaa874422013-09-18 19:43:12 -0700529 }
530 }
531 }
532
Seth Raphaelcbd82672013-11-05 10:12:36 -0800533 private String fileNameFromDataID(int dataID) {
534 final LocalData localData = mDataAdapter.getLocalData(dataID);
535
536 File localFile = new File(localData.getPath());
537 return localFile.getName();
538 }
539
Angus Kong01054e92013-12-10 11:06:18 -0800540 private final FilmstripContentPanel.Listener mFilmstripListener =
541 new FilmstripContentPanel.Listener() {
Angus Kongfaaee012013-12-07 00:38:46 -0800542
543 @Override
Erin Dahlgren34881882014-01-29 18:13:34 -0800544 public void onSwipeOut() {
Erin Dahlgren34881882014-01-29 18:13:34 -0800545 }
546
547 @Override
Angus Kong73e09f32014-02-25 23:45:52 -0800548 public void onSwipeOutBegin() {
549 mActionBar.hide();
Sascha Haeberling2d11fcf2014-03-13 09:04:32 -0700550 mFilmstripCoversPreview = false;
551 updatePreviewVisibility();
Angus Kong73e09f32014-02-25 23:45:52 -0800552 }
553
554 @Override
Angus Kongfaaee012013-12-07 00:38:46 -0800555 public void onFilmstripHidden() {
556 mFilmstripVisible = false;
Andy Huibers10c58162014-03-29 14:06:54 -0700557 UsageStatistics.instance().changeScreen(currentUserInterfaceMode(),
558 NavigationChange.InteractionCause.SWIPE_RIGHT);
Angus Kongb2510252013-12-10 22:58:15 -0800559 CameraActivity.this.setFilmstripUiVisibility(false);
Angus Kongfaaee012013-12-07 00:38:46 -0800560 // When the user hide the filmstrip (either swipe out or
561 // tap on back key) we move to the first item so next time
562 // when the user swipe in the filmstrip, the most recent
563 // one is shown.
564 mFilmstripController.goToFirstItem();
Angus Kongfaaee012013-12-07 00:38:46 -0800565 }
566
567 @Override
568 public void onFilmstripShown() {
569 mFilmstripVisible = true;
Andy Huibers10c58162014-03-29 14:06:54 -0700570 UsageStatistics.instance().changeScreen(currentUserInterfaceMode(),
571 NavigationChange.InteractionCause.SWIPE_LEFT);
Angus Kongfaaee012013-12-07 00:38:46 -0800572 updateUiByData(mFilmstripController.getCurrentId());
Angus Kongfaaee012013-12-07 00:38:46 -0800573 }
574
Sascha Haeberling37f36112013-08-06 14:31:52 -0700575 @Override
Angus Kong26795a92014-02-20 09:18:09 -0800576 public void onFocusedDataLongPressed(int dataId) {
Sascha Haeberlingd114a772014-02-28 21:27:27 -0800577 // Do nothing.
Angus Kong26795a92014-02-20 09:18:09 -0800578 }
579
580 @Override
581 public void onFocusedDataPromoted(int dataID) {
Andy Huibers10c58162014-03-29 14:06:54 -0700582 UsageStatistics.instance().mediaInteraction(fileNameFromDataID(dataID),
583 MediaInteraction.InteractionType.DELETE,
584 NavigationChange.InteractionCause.SWIPE_UP);
Sascha Haeberling37f36112013-08-06 14:31:52 -0700585 removeData(dataID);
586 }
Doris Liu6432cd62013-06-13 17:20:31 -0700587
Sascha Haeberling37f36112013-08-06 14:31:52 -0700588 @Override
Angus Kong26795a92014-02-20 09:18:09 -0800589 public void onFocusedDataDemoted(int dataID) {
Andy Huibers10c58162014-03-29 14:06:54 -0700590 UsageStatistics.instance().mediaInteraction(fileNameFromDataID(dataID),
591 MediaInteraction.InteractionType.DELETE,
592 NavigationChange.InteractionCause.SWIPE_DOWN);
Sascha Haeberling37f36112013-08-06 14:31:52 -0700593 removeData(dataID);
594 }
Doris Liu6432cd62013-06-13 17:20:31 -0700595
Sascha Haeberling37f36112013-08-06 14:31:52 -0700596 @Override
Angus Kong45671602014-01-13 15:06:17 -0800597 public void onEnterFullScreenUiShown(int dataId) {
598 if (mFilmstripVisible) {
599 CameraActivity.this.setFilmstripUiVisibility(true);
600 }
601 }
602
603 @Override
604 public void onLeaveFullScreenUiShown(int dataId) {
605 // Do nothing.
606 }
607
608 @Override
609 public void onEnterFullScreenUiHidden(int dataId) {
Angus Kongfaaee012013-12-07 00:38:46 -0800610 if (mFilmstripVisible) {
Angus Kongb2510252013-12-10 22:58:15 -0800611 CameraActivity.this.setFilmstripUiVisibility(false);
Erin Dahlgren3044d8c2013-10-10 18:23:45 -0700612 }
613 }
614
615 @Override
Angus Kong45671602014-01-13 15:06:17 -0800616 public void onLeaveFullScreenUiHidden(int dataId) {
Angus Kongfaaee012013-12-07 00:38:46 -0800617 // Do nothing.
618 }
Erin Dahlgren3044d8c2013-10-10 18:23:45 -0700619
Angus Kongfaaee012013-12-07 00:38:46 -0800620 @Override
621 public void onEnterFilmstrip(int dataId) {
622 if (mFilmstripVisible) {
Angus Kongb2510252013-12-10 22:58:15 -0800623 CameraActivity.this.setFilmstripUiVisibility(true);
Erin Dahlgren3044d8c2013-10-10 18:23:45 -0700624 }
625 }
626
627 @Override
Angus Kongfaaee012013-12-07 00:38:46 -0800628 public void onLeaveFilmstrip(int dataId) {
Angus Kong601c8c12014-02-21 10:01:58 -0800629 // Do nothing.
Angus Kongfaaee012013-12-07 00:38:46 -0800630 }
631
632 @Override
633 public void onDataReloaded() {
634 if (!mFilmstripVisible) {
635 return;
636 }
637 updateUiByData(mFilmstripController.getCurrentId());
638 }
639
640 @Override
Angus Kong8a2350a2013-12-16 15:02:34 -0800641 public void onDataUpdated(int dataId) {
642 if (!mFilmstripVisible) {
643 return;
644 }
645 updateUiByData(mFilmstripController.getCurrentId());
646 }
647
648 @Override
Angus Kongfaaee012013-12-07 00:38:46 -0800649 public void onEnterZoomView(int dataID) {
650 if (mFilmstripVisible) {
Angus Kongb2510252013-12-10 22:58:15 -0800651 CameraActivity.this.setFilmstripUiVisibility(false);
Angus Kongfaaee012013-12-07 00:38:46 -0800652 }
653 }
654
655 @Override
656 public void onDataFocusChanged(final int prevDataId, final int newDataId) {
657 if (!mFilmstripVisible) {
658 return;
Doris Liuaa874422013-09-18 19:43:12 -0700659 }
Angus Kong02cafdf2013-10-13 19:26:02 -0700660 // TODO: This callback is UI event callback, should always
661 // happen on UI thread. Find the reason for this
662 // runOnUiThread() and fix it.
Mangesh Ghiware33035c12013-08-23 13:28:21 -0700663 runOnUiThread(new Runnable() {
664 @Override
665 public void run() {
Angus Kongfaaee012013-12-07 00:38:46 -0800666 updateUiByData(newDataId);
ztenghui2c3d9a52013-09-03 11:27:21 -0700667 }
Mangesh Ghiware33035c12013-08-23 13:28:21 -0700668 });
Sascha Haeberling37f36112013-08-06 14:31:52 -0700669 }
Sam Juddde3e9ab2014-03-17 13:07:22 -0700670
671 @Override
672 public void onScroll(int firstVisiblePosition, int visibleItemCount, int totalItemCount) {
673 mPreloader.onScroll(null /*absListView*/, firstVisiblePosition, visibleItemCount, totalItemCount);
674 }
Sascha Haeberling37f36112013-08-06 14:31:52 -0700675 };
676
Sascha Haeberling44c1afb2013-12-20 11:59:35 -0800677 private final LocalDataAdapter.LocalDataListener mLocalDataListener =
Angus Konge2f4c032013-12-19 10:24:33 -0800678 new LocalDataAdapter.LocalDataListener() {
679 @Override
680 public void onMetadataUpdated(List<Integer> updatedData) {
681 int currentDataId = mFilmstripController.getCurrentId();
682 for (Integer dataId : updatedData) {
683 if (dataId == currentDataId) {
684 updateBottomControlsByData(mDataAdapter.getLocalData(dataId));
685 }
686 }
687 }
688 };
689
Sascha Haeberling4ed20592013-09-13 11:58:33 -0700690 public void gotoGallery() {
Sascha Haeberlinga83ec8a2014-03-31 13:22:17 -0700691 UsageStatistics.instance().changeScreen(NavigationChange.Mode.FILMSTRIP,
Andy Huibers10c58162014-03-29 14:06:54 -0700692 NavigationChange.InteractionCause.BUTTON);
Seth Raphaelcbd82672013-11-05 10:12:36 -0800693
Angus Kong62848152013-11-08 17:25:29 -0800694 mFilmstripController.goToNextItem();
Sascha Haeberling4ed20592013-09-13 11:58:33 -0700695 }
696
Sascha Haeberling5199c202013-09-05 17:10:19 -0700697 /**
Sascha Haeberling099b49b2014-04-08 07:08:46 -0700698 * If 'visible' is false, this hides the action bar. Also maintains
699 * lights-out at all times.
Sascha Haeberling846d3ab2014-02-04 12:48:55 +0100700 *
Sascha Haeberling099b49b2014-04-08 07:08:46 -0700701 * @param visible is false, this hides the action bar and filmstrip bottom
702 * controls.
Sascha Haeberling5199c202013-09-05 17:10:19 -0700703 */
Angus Kong601c8c12014-02-21 10:01:58 -0800704 private void setFilmstripUiVisibility(boolean visible) {
Sascha Haeberling099b49b2014-04-08 07:08:46 -0700705 mLightsOutRunnable.run();
Angus Kongb2510252013-12-10 22:58:15 -0800706 mCameraAppUI.getFilmstripBottomControls().setVisible(visible);
Angus Kong001dc312014-02-27 16:58:11 -0800707 if (visible != mActionBar.isShowing()) {
Doris Liuaa874422013-09-18 19:43:12 -0700708 if (visible) {
709 mActionBar.show();
710 } else {
711 mActionBar.hide();
712 }
Doris Liuaa874422013-09-18 19:43:12 -0700713 }
Sascha Haeberling2d11fcf2014-03-13 09:04:32 -0700714 mFilmstripCoversPreview = visible;
715 updatePreviewVisibility();
Sascha Haeberling5199c202013-09-05 17:10:19 -0700716 }
717
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800718 private void hideSessionProgress() {
Angus Kong001dc312014-02-27 16:58:11 -0800719 mCameraAppUI.getFilmstripBottomControls().hideProgress();
Sascha Haeberling37f36112013-08-06 14:31:52 -0700720 }
721
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800722 private void showSessionProgress(CharSequence message) {
Sascha Haeberling099b49b2014-04-08 07:08:46 -0700723 CameraAppUI.BottomPanel controls = mCameraAppUI.getFilmstripBottomControls();
Angus Kong7ae25c22014-02-25 10:37:39 -0800724 controls.setProgressText(message);
Angus Kong001dc312014-02-27 16:58:11 -0800725 controls.hideControls();
Sascha Haeberling597c1a02014-03-06 11:46:06 -0800726 controls.hideProgressError();
Angus Kong7ae25c22014-02-25 10:37:39 -0800727 controls.showProgress();
Sascha Haeberling37f36112013-08-06 14:31:52 -0700728 }
729
Sascha Haeberling597c1a02014-03-06 11:46:06 -0800730 private void showProcessError(CharSequence message) {
731 mCameraAppUI.getFilmstripBottomControls().showProgressError(message);
732 }
733
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800734 private void updateSessionProgress(int progress) {
Angus Kong7ae25c22014-02-25 10:37:39 -0800735 mCameraAppUI.getFilmstripBottomControls().setProgress(progress);
Sascha Haeberling37f36112013-08-06 14:31:52 -0700736 }
Doris Liu6432cd62013-06-13 17:20:31 -0700737
Carlos Hernandezcbd058a2014-03-25 12:26:19 -0700738 private void updateSessionProgressText(CharSequence message) {
739 mCameraAppUI.getFilmstripBottomControls().setProgressText(message);
740 }
741
Mangesh Ghiwarea5682ab2013-09-19 09:24:23 -0700742 @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
743 private void setupNfcBeamPush() {
Sascha Haeberling846d3ab2014-02-04 12:48:55 +0100744 NfcAdapter adapter = NfcAdapter.getDefaultAdapter(mAppContext);
Mangesh Ghiwarea5682ab2013-09-19 09:24:23 -0700745 if (adapter == null) {
746 return;
747 }
748
749 if (!ApiHelper.HAS_SET_BEAM_PUSH_URIS) {
750 // Disable beaming
751 adapter.setNdefPushMessage(null, CameraActivity.this);
752 return;
753 }
754
755 adapter.setBeamPushUris(null, CameraActivity.this);
756 adapter.setBeamPushUrisCallback(new CreateBeamUrisCallback() {
757 @Override
758 public Uri[] createBeamUris(NfcEvent event) {
759 return mNfcPushUris;
760 }
761 }, CameraActivity.this);
762 }
763
Doris Liuaa874422013-09-18 19:43:12 -0700764 @Override
765 public void onMenuVisibilityChanged(boolean isVisible) {
Angus Kongfaaee012013-12-07 00:38:46 -0800766 // TODO: Remove this or bring back the original implementation: cancel
767 // auto-hide actionbar.
Doris Liuaa874422013-09-18 19:43:12 -0700768 }
769
Seth Raphaelcbd82672013-11-05 10:12:36 -0800770 @Override
771 public boolean onShareTargetSelected(ShareActionProvider shareActionProvider, Intent intent) {
Angus Kong62848152013-11-08 17:25:29 -0800772 int currentDataId = mFilmstripController.getCurrentId();
Seth Raphaelcbd82672013-11-05 10:12:36 -0800773 if (currentDataId < 0) {
774 return false;
775 }
Andy Huibers10c58162014-03-29 14:06:54 -0700776 UsageStatistics.instance().mediaInteraction(fileNameFromDataID(currentDataId),
777 MediaInteraction.InteractionType.SHARE,
778 NavigationChange.InteractionCause.BUTTON);
Sascha Haeberling846d3ab2014-02-04 12:48:55 +0100779 // TODO add intent.getComponent().getPackageName()
Seth Raphaelcbd82672013-11-05 10:12:36 -0800780 return true;
781 }
782
Sascha Haeberling14ff6c82013-12-13 13:29:58 -0800783 // Note: All callbacks come back on the main thread.
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800784 private final SessionListener mSessionListener =
785 new SessionListener() {
Ruben Brunk7cfcafd2013-10-17 15:41:44 -0700786 @Override
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800787 public void onSessionQueued(final Uri uri) {
Angus Kong571a8c32014-03-13 12:53:03 -0700788 if (!Storage.isSessionUri(uri)) {
789 return;
790 }
791 LocalSessionData newData = new LocalSessionData(uri);
792 mDataAdapter.addData(newData);
Angus Kong6798c342013-07-16 15:14:58 -0700793 }
794
795 @Override
Angus Kong571a8c32014-03-13 12:53:03 -0700796 public void onSessionDone(final Uri sessionUri) {
797 Log.v(TAG, "onSessionDone:" + sessionUri);
798 Uri contentUri = Storage.getContentUriForSessionUri(sessionUri);
799 if (contentUri == null) {
800 mDataAdapter.refresh(sessionUri);
801 return;
802 }
803 LocalData newData = LocalMediaData.PhotoData.fromContentUri(
804 getContentResolver(), contentUri);
805
806 final int pos = mDataAdapter.findDataByContentUri(sessionUri);
807 if (pos == -1) {
Sascha Haeberling099b49b2014-04-08 07:08:46 -0700808 // We do not have a placeholder for this image, perhaps
809 // due to the activity crashing or being killed.
Angus Kong571a8c32014-03-13 12:53:03 -0700810 mDataAdapter.addData(newData);
Sascha Haeberling099b49b2014-04-08 07:08:46 -0700811 } else {
Angus Kong571a8c32014-03-13 12:53:03 -0700812 mDataAdapter.updateData(pos, newData);
813 }
Angus Kong6798c342013-07-16 15:14:58 -0700814 }
815
816 @Override
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800817 public void onSessionProgress(final Uri uri, final int progress) {
818 if (progress < 0) {
819 // Do nothing, there is no task for this URI.
820 return;
821 }
Sascha Haeberling14ff6c82013-12-13 13:29:58 -0800822 int currentDataId = mFilmstripController.getCurrentId();
823 if (currentDataId == -1) {
824 return;
825 }
826 if (uri.equals(
Angus Kong571a8c32014-03-13 12:53:03 -0700827 mDataAdapter.getLocalData(currentDataId).getUri())) {
Sascha Haeberling14ff6c82013-12-13 13:29:58 -0800828 updateSessionProgress(progress);
829 }
830 }
831
832 @Override
Carlos Hernandezcbd058a2014-03-25 12:26:19 -0700833 public void onSessionProgressText(final Uri uri, final CharSequence message) {
834 int currentDataId = mFilmstripController.getCurrentId();
835 if (currentDataId == -1) {
836 return;
837 }
838 if (uri.equals(
839 mDataAdapter.getLocalData(currentDataId).getUri())) {
840 updateSessionProgressText(message);
841 }
842 }
843
844 @Override
Sascha Haeberling14ff6c82013-12-13 13:29:58 -0800845 public void onSessionUpdated(Uri uri) {
Seth Raphael455ba5a2014-02-13 15:10:06 -0800846 mDataAdapter.refresh(uri);
Angus Kong6798c342013-07-16 15:14:58 -0700847 }
Sascha Haeberling597c1a02014-03-06 11:46:06 -0800848
849 @Override
Angus Kong571a8c32014-03-13 12:53:03 -0700850 public void onSessionPreviewAvailable(Uri uri) {
851 mDataAdapter.refresh(uri);
852 int dataId = mDataAdapter.findDataByContentUri(uri);
853 if (dataId != -1) {
854 startPeekAnimation(mDataAdapter.getLocalData(dataId));
855 }
856 }
857
858 @Override
Sascha Haeberling597c1a02014-03-06 11:46:06 -0800859 public void onSessionFailed(Uri uri, CharSequence reason) {
860 Log.v(TAG, "onSessionFailed:" + uri);
861
862 int failedDataId = mDataAdapter.findDataByContentUri(uri);
863 int currentDataId = mFilmstripController.getCurrentId();
864
865 if (currentDataId == failedDataId) {
866 updateSessionProgress(0);
867 showProcessError(reason);
868 }
Seth Raphael455ba5a2014-02-13 15:10:06 -0800869 // HERE
870 mDataAdapter.refresh(uri);
Sascha Haeberling597c1a02014-03-06 11:46:06 -0800871 }
Angus Kong6798c342013-07-16 15:14:58 -0700872 };
873
Angus Kong9f1db522013-11-09 16:25:59 -0800874 @Override
875 public Context getAndroidContext() {
Sascha Haeberling846d3ab2014-02-04 12:48:55 +0100876 return mAppContext;
Angus Kong9f1db522013-11-09 16:25:59 -0800877 }
878
879 @Override
Angus Kong0eaf0162013-12-16 15:53:30 -0800880 public void launchActivityByIntent(Intent intent) {
881 startActivityForResult(intent, REQ_CODE_DONT_SWITCH_TO_PREVIEW);
882 }
883
884 @Override
Doris Liuf55f3c42013-11-20 00:24:46 -0800885 public int getCurrentModuleIndex() {
886 return mCurrentModeIndex;
887 }
888
889 @Override
Erin Dahlgren0a6a8d82014-01-09 22:17:38 -0800890 public ModuleController getCurrentModuleController() {
Sascha Haeberling8793eff2014-01-15 16:33:59 -0800891 return mCurrentModule;
Erin Dahlgren0a6a8d82014-01-09 22:17:38 -0800892 }
893
894 @Override
Doris Liubd1b8f92014-01-03 17:59:51 -0800895 public int getQuickSwitchToModuleId(int currentModuleIndex) {
Sascha Haeberling846d3ab2014-02-04 12:48:55 +0100896 return mModuleManager.getQuickSwitchToModuleId(currentModuleIndex, mSettingsManager,
897 mAppContext);
Doris Liubd1b8f92014-01-03 17:59:51 -0800898 }
899
900 @Override
Angus Kong9f1db522013-11-09 16:25:59 -0800901 public SurfaceTexture getPreviewBuffer() {
902 // TODO: implement this
903 return null;
904 }
905
906 @Override
Doris Liu5a367542014-01-17 17:21:42 -0800907 public void onPreviewReadyToStart() {
908 mCameraAppUI.onPreviewReadyToStart();
909 }
910
911 @Override
Doris Liu2b906b82013-12-10 16:34:08 -0800912 public void onPreviewStarted() {
913 mCameraAppUI.onPreviewStarted();
914 }
915
916 @Override
Doris Liu482de022013-12-18 19:18:16 -0800917 public void addPreviewAreaSizeChangedListener(
Angus Kong2bacca72014-03-06 12:57:29 -0800918 PreviewStatusListener.PreviewAreaChangedListener listener) {
919 mCameraAppUI.addPreviewAreaChangedListener(listener);
Doris Liu482de022013-12-18 19:18:16 -0800920 }
921
922 @Override
923 public void removePreviewAreaSizeChangedListener(
Angus Kong2bacca72014-03-06 12:57:29 -0800924 PreviewStatusListener.PreviewAreaChangedListener listener) {
925 mCameraAppUI.removePreviewAreaChangedListener(listener);
Doris Liu482de022013-12-18 19:18:16 -0800926 }
927
928 @Override
Doris Liu4d4a4bc2013-12-19 18:55:54 -0800929 public void setupOneShotPreviewListener() {
930 mCameraController.setOneShotPreviewCallback(mMainHandler,
931 new CameraManager.CameraPreviewDataCallback() {
Doris Liu482de022013-12-18 19:18:16 -0800932 @Override
933 public void onPreviewFrame(byte[] data, CameraManager.CameraProxy camera) {
Seth Raphael30836422014-02-06 14:49:47 -0800934 mCurrentModule.onPreviewInitialDataReceived();
Doris Liu482de022013-12-18 19:18:16 -0800935 mCameraAppUI.onNewPreviewFrame();
936 }
Angus Kong5596b4c2014-03-11 16:27:30 -0700937 }
938 );
Doris Liu4d4a4bc2013-12-19 18:55:54 -0800939 }
940
941 @Override
Doris Liu70da9182013-12-17 18:41:15 -0800942 public void updatePreviewAspectRatio(float aspectRatio) {
943 mCameraAppUI.updatePreviewAspectRatio(aspectRatio);
944 }
945
946 @Override
947 public void updatePreviewTransform(Matrix matrix) {
948 mCameraAppUI.updatePreviewTransform(matrix);
949 }
950
951 @Override
Doris Liu06db7422013-12-09 19:36:25 -0800952 public void setPreviewStatusListener(PreviewStatusListener previewStatusListener) {
953 mCameraAppUI.setPreviewStatusListener(previewStatusListener);
954 }
955
956 @Override
Angus Kong9f1db522013-11-09 16:25:59 -0800957 public FrameLayout getModuleLayoutRoot() {
Doris Liuc6c97402013-12-06 21:02:53 -0800958 return mCameraAppUI.getModuleRootView();
Angus Kong9f1db522013-11-09 16:25:59 -0800959 }
960
961 @Override
962 public void setShutterEventsListener(ShutterEventsListener listener) {
963 // TODO: implement this
964 }
965
966 @Override
967 public void setShutterEnabled(boolean enabled) {
Erin Dahlgren667630d2014-04-01 14:03:25 -0700968 mCameraAppUI.setShutterButtonEnabled(enabled);
Angus Kong9f1db522013-11-09 16:25:59 -0800969 }
970
971 @Override
972 public boolean isShutterEnabled() {
Erin Dahlgren667630d2014-04-01 14:03:25 -0700973 return mCameraAppUI.isShutterButtonEnabled();
Angus Kong9f1db522013-11-09 16:25:59 -0800974 }
975
976 @Override
977 public void startPreCaptureAnimation() {
Doris Liu1dfe7822013-12-12 00:02:08 -0800978 mCameraAppUI.startPreCaptureAnimation();
Angus Kong9f1db522013-11-09 16:25:59 -0800979 }
980
981 @Override
982 public void cancelPreCaptureAnimation() {
983 // TODO: implement this
984 }
985
986 @Override
987 public void startPostCaptureAnimation() {
988 // TODO: implement this
989 }
990
991 @Override
992 public void startPostCaptureAnimation(Bitmap thumbnail) {
993 // TODO: implement this
994 }
995
996 @Override
997 public void cancelPostCaptureAnimation() {
998 // TODO: implement this
999 }
1000
1001 @Override
Angus Kong9f1db522013-11-09 16:25:59 -08001002 public OrientationManager getOrientationManager() {
1003 return mOrientationManager;
1004 }
1005
1006 @Override
1007 public LocationManager getLocationManager() {
Erin Dahlgren21c21a62013-11-19 16:37:38 -08001008 return mLocationManager;
Angus Kong9f1db522013-11-09 16:25:59 -08001009 }
1010
1011 @Override
1012 public void lockOrientation() {
Sascha Haeberlingba29a442014-02-26 16:43:19 -08001013 if (mOrientationManager != null) {
1014 mOrientationManager.lockOrientation();
1015 }
Angus Kong9f1db522013-11-09 16:25:59 -08001016 }
1017
1018 @Override
1019 public void unlockOrientation() {
Sascha Haeberlingba29a442014-02-26 16:43:19 -08001020 if (mOrientationManager != null) {
1021 mOrientationManager.unlockOrientation();
1022 }
Angus Kong9f1db522013-11-09 16:25:59 -08001023 }
1024
Angus Kong50521172014-01-17 17:23:59 -08001025 /**
1026 * Starts the filmstrip peek animation if the filmstrip is not visible.
1027 * Only {@link LocalData#LOCAL_IMAGE}, {@link
1028 * LocalData#LOCAL_IN_PROGRESS_DATA} and {@link
1029 * LocalData#LOCAL_VIDEO} are supported.
1030 *
1031 * @param data The data to peek.
1032 */
1033 private void startPeekAnimation(final LocalData data) {
1034 if (mFilmstripVisible || mPeekAnimationHandler == null) {
1035 return;
1036 }
1037
1038 int dataType = data.getLocalDataType();
1039 if (dataType != LocalData.LOCAL_IMAGE && dataType != LocalData.LOCAL_IN_PROGRESS_DATA &&
1040 dataType != LocalData.LOCAL_VIDEO) {
1041 return;
1042 }
1043
Angus Kongc195e7a2014-02-20 16:56:37 -08001044 mPeekAnimationHandler.startDecodingJob(data, new Callback<Bitmap>() {
Angus Kong50521172014-01-17 17:23:59 -08001045 @Override
1046 public void onCallback(Bitmap result) {
1047 mCameraAppUI.startPeekAnimation(result, true);
1048 }
1049 });
1050 }
1051
Angus Kong9f1db522013-11-09 16:25:59 -08001052 @Override
Doris Liu6432cd62013-06-13 17:20:31 -07001053 public void notifyNewMedia(Uri uri) {
Spike Spraguee6374b72014-04-25 17:24:32 -07001054 updateStorageSpaceAndHint(null);
Angus Kong571a8c32014-03-13 12:53:03 -07001055 ContentResolver cr = getContentResolver();
1056 String mimeType = cr.getType(uri);
1057 if (LocalDataUtil.isMimeTypeVideo(mimeType)) {
1058 sendBroadcast(new Intent(CameraUtil.ACTION_NEW_VIDEO, uri));
1059 LocalData newData = LocalMediaData.VideoData.fromContentUri(getContentResolver(), uri);
1060 if (newData == null) {
1061 Log.e(TAG, "Can't find video data in content resolver:" + uri);
1062 return;
Seth Raphael455ba5a2014-02-13 15:10:06 -08001063 }
Angus Kong571a8c32014-03-13 12:53:03 -07001064 if (mDataAdapter.addData(newData)) {
1065 startPeekAnimation(newData);
1066 }
1067 } else if (LocalDataUtil.isMimeTypeImage(mimeType)) {
1068 CameraUtil.broadcastNewPicture(mAppContext, uri);
1069 LocalData newData = LocalMediaData.PhotoData.fromContentUri(getContentResolver(), uri);
1070 if (newData == null) {
1071 Log.e(TAG, "Can't find photo data in content resolver:" + uri);
1072 return;
1073 }
1074 if (mDataAdapter.addData(newData)) {
1075 startPeekAnimation(newData);
1076 }
1077 } else {
Angus Kong5596b4c2014-03-11 16:27:30 -07001078 Log.w(TAG, "Unknown new media with MIME type:" + mimeType + ", uri:" + uri);
Doris Liu48239f42013-03-04 22:19:10 -08001079 }
1080 }
1081
Angus Kong20fad242013-11-11 18:23:46 -08001082 @Override
Angus Kong13e87c42013-11-25 10:02:47 -08001083 public void enableKeepScreenOn(boolean enabled) {
1084 if (mPaused) {
1085 return;
1086 }
1087
1088 mKeepScreenOn = enabled;
1089 if (mKeepScreenOn) {
1090 mMainHandler.removeMessages(MSG_CLEAR_SCREEN_ON_FLAG);
1091 getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
1092 } else {
1093 keepScreenOnForAWhile();
1094 }
1095 }
1096
1097 @Override
Angus Kong20fad242013-11-11 18:23:46 -08001098 public CameraProvider getCameraProvider() {
1099 return mCameraController;
1100 }
1101
Doris Liu6432cd62013-06-13 17:20:31 -07001102 private void removeData(int dataID) {
Sascha Haeberling44c1afb2013-12-20 11:59:35 -08001103 mDataAdapter.removeData(dataID);
Doris Liu742cd5b2013-09-12 16:17:43 -07001104 if (mDataAdapter.getTotalNumber() > 1) {
1105 showUndoDeletionBar();
1106 } else {
1107 // If camera preview is the only view left in filmstrip,
1108 // no need to show undo bar.
Doris Liuf2c14332013-09-26 11:24:37 -07001109 mPendingDeletion = true;
Doris Liu742cd5b2013-09-12 16:17:43 -07001110 performDeletion();
Angus Kong1f9db2d2014-01-09 00:56:35 -08001111 if (mFilmstripVisible) {
1112 mCameraAppUI.getFilmstripContentPanel().animateHide();
1113 }
Doris Liu742cd5b2013-09-12 16:17:43 -07001114 }
Michael Kolb8872c232013-01-29 10:33:22 -08001115 }
1116
ztenghui0353ca22013-08-13 13:53:16 -07001117 @Override
1118 public boolean onOptionsItemSelected(MenuItem item) {
1119 // Handle presses on the action bar items
1120 switch (item.getItemId()) {
Alan Newberger3f969c12013-08-23 10:10:30 -07001121 case android.R.id.home:
Angus Kong601c8c12014-02-21 10:01:58 -08001122 if (mFilmstripVisible && startGallery()) {
Angus Kong6c0c7f12014-01-15 14:40:27 -08001123 return true;
Emil Arfvidssonf05962f2013-12-26 14:40:34 -08001124 }
Angus Kong6c0c7f12014-01-15 14:40:27 -08001125 onBackPressed();
Angus Kong248f42b2013-12-06 15:49:17 -08001126 return true;
Sascha Haeberlingd114a772014-02-28 21:27:27 -08001127 case R.id.action_details:
1128 showDetailsDialog(mFilmstripController.getCurrentId());
1129 return true;
ztenghui0353ca22013-08-13 13:53:16 -07001130 default:
1131 return super.onOptionsItemSelected(item);
1132 }
1133 }
1134
ztenghuifd43e3b2013-09-03 11:30:11 -07001135 private boolean isCaptureIntent() {
1136 if (MediaStore.ACTION_VIDEO_CAPTURE.equals(getIntent().getAction())
1137 || MediaStore.ACTION_IMAGE_CAPTURE.equals(getIntent().getAction())
1138 || MediaStore.ACTION_IMAGE_CAPTURE_SECURE.equals(getIntent().getAction())) {
1139 return true;
1140 } else {
1141 return false;
1142 }
1143 }
1144
Erin Dahlgren630d55b2014-03-10 14:40:59 -07001145 private final CameraManager.CameraExceptionCallback mCameraDefaultExceptionCallback
1146 = new CameraManager.CameraExceptionCallback() {
1147 @Override
1148 public void onCameraException(RuntimeException e) {
Alan Newbergerd41766f2014-04-09 18:25:34 -07001149 Log.e(TAG, "Camera Exception", e);
Erin Dahlgren630d55b2014-03-10 14:40:59 -07001150 CameraUtil.showErrorAndFinish(CameraActivity.this,
1151 R.string.cannot_connect_camera);
1152 }
1153 };
Sascha Haeberlingd114a772014-02-28 21:27:27 -08001154
ztenghui0353ca22013-08-13 13:53:16 -07001155 @Override
Doris Liu6432cd62013-06-13 17:20:31 -07001156 public void onCreate(Bundle state) {
Doris Liu7cbecee2014-01-30 12:29:27 -08001157 CameraPerformanceTracker.onEvent(CameraPerformanceTracker.ACTIVITY_START);
Erin Dahlgren5f38da82014-04-01 11:48:40 -07001158
1159 super.onCreate(state);
Kevin Gabayana0e83472014-01-15 15:21:13 -08001160 mOnCreateTime = System.currentTimeMillis();
Sascha Haeberling846d3ab2014-02-04 12:48:55 +01001161 mAppContext = getApplicationContext();
Sascha Haeberlinge3e270f2014-04-02 23:27:50 -07001162 mSettingsManager = new SettingsManager(mAppContext, this);
Sascha Haeberling048bf4d2013-10-06 17:49:51 -07001163 GcamHelper.init(getContentResolver());
1164
ztenghui50df4702013-08-13 15:53:57 -07001165 getWindow().requestFeature(Window.FEATURE_ACTION_BAR);
Doris Liu1c94b7d2013-11-09 19:13:44 -08001166 setContentView(R.layout.activity_main);
ztenghuifa9e2cc2013-08-09 17:37:15 -07001167 mActionBar = getActionBar();
Doris Liuaa874422013-09-18 19:43:12 -07001168 mActionBar.addOnMenuVisibilityListener(this);
Sascha Haeberling846d3ab2014-02-04 12:48:55 +01001169 mMainHandler = new MainHandler(this, getMainLooper());
Angus Kong20fad242013-11-11 18:23:46 -08001170 mCameraController =
Sascha Haeberling846d3ab2014-02-04 12:48:55 +01001171 new CameraController(mAppContext, this, mMainHandler,
Angus Kong20fad242013-11-11 18:23:46 -08001172 CameraManagerFactory.getAndroidCameraManager());
Erin Dahlgren630d55b2014-03-10 14:40:59 -07001173 mCameraController.setCameraDefaultExceptionCallback(mCameraDefaultExceptionCallback,
1174 mMainHandler);
1175
Angus Kong20fad242013-11-11 18:23:46 -08001176 // TODO: Try to move all the resources allocation to happen as soon as
1177 // possible so we can call module.init() at the earliest time.
1178 mModuleManager = new ModuleManagerImpl();
Sascha Haeberling846d3ab2014-02-04 12:48:55 +01001179 ModulesInfo.setupModules(mAppContext, mModuleManager);
ztenghuifa9e2cc2013-08-09 17:37:15 -07001180
Doris Liu70576b62013-11-14 20:30:33 -08001181 mModeListView = (ModeListView) findViewById(R.id.mode_list_layout);
Doris Liua20074f2013-12-09 15:19:06 -08001182 mModeListView.init(mModuleManager.getSupportedModeIndexList());
Michael Kolb08650182013-02-25 19:43:56 -08001183 if (ApiHelper.HAS_ROTATION_ANIMATION) {
Doris Liu6432cd62013-06-13 17:20:31 -07001184 setRotationAnimation();
Michael Kolb08650182013-02-25 19:43:56 -08001185 }
Sascha Haeberling8c1a9222014-02-25 09:38:06 -08001186 mModeListView.setVisibilityChangedListener(new ModeListVisibilityChangedListener() {
1187 @Override
1188 public void onVisibilityChanged(boolean visible) {
Sascha Haeberling2d11fcf2014-03-13 09:04:32 -07001189 mModeListVisible = visible;
1190 updatePreviewVisibility();
Sascha Haeberling8c1a9222014-02-25 09:38:06 -08001191 }
1192 });
Doris Liuaa874422013-09-18 19:43:12 -07001193
Doris Liu6432cd62013-06-13 17:20:31 -07001194 // Check if this is in the secure camera mode.
1195 Intent intent = getIntent();
1196 String action = intent.getAction();
Doris Liub84b9732013-06-18 17:14:26 -07001197 if (INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE.equals(action)
1198 || ACTION_IMAGE_CAPTURE_SECURE.equals(action)) {
Doris Liu6432cd62013-06-13 17:20:31 -07001199 mSecureCamera = true;
1200 } else {
1201 mSecureCamera = intent.getBooleanExtra(SECURE_CAMERA_EXTRA, false);
1202 }
Doris Liub84b9732013-06-18 17:14:26 -07001203
1204 if (mSecureCamera) {
Erin Dahlgrenf6edd532014-01-31 11:13:33 -08001205 // Foreground event caused by lock screen startup.
1206 // It is necessary to log this in onCreate, to avoid the
1207 // onResume->onPause->onResume sequence.
Andy Huibers10c58162014-03-29 14:06:54 -07001208 UsageStatistics.instance().foregrounded(ForegroundSource.ACTION_IMAGE_CAPTURE_SECURE,
1209 currentUserInterfaceMode());
Erin Dahlgrenf6edd532014-01-31 11:13:33 -08001210
Sascha Haeberling846d3ab2014-02-04 12:48:55 +01001211 // Change the window flags so that secure camera can show when
1212 // locked
Doris Liub84b9732013-06-18 17:14:26 -07001213 Window win = getWindow();
1214 WindowManager.LayoutParams params = win.getAttributes();
1215 params.flags |= WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
1216 win.setAttributes(params);
1217
Sascha Haeberling846d3ab2014-02-04 12:48:55 +01001218 // Filter for screen off so that we can finish secure camera
1219 // activity
Doris Liub84b9732013-06-18 17:14:26 -07001220 // when screen is off.
Doris Liu6432cd62013-06-13 17:20:31 -07001221 IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_OFF);
1222 registerReceiver(mScreenOffReceiver, filter);
Doris Liub84b9732013-06-18 17:14:26 -07001223 }
Angus Kongb2510252013-12-10 22:58:15 -08001224 mCameraAppUI = new CameraAppUI(this,
Sascha Haeberling8793eff2014-01-15 16:33:59 -08001225 (MainActivityLayout) findViewById(R.id.activity_root_view), isCaptureIntent());
Angus Kongb2510252013-12-10 22:58:15 -08001226
1227 mCameraAppUI.setFilmstripBottomControlsListener(mMyFilmstripBottomControlListener);
1228
Angus Kong653c43b2013-08-21 18:28:43 -07001229 mAboveFilmstripControlLayout =
Angus Kongb95699e2013-12-07 13:52:51 -08001230 (FrameLayout) findViewById(R.id.camera_filmstrip_content_layout);
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001231
Sascha Haeberling846d3ab2014-02-04 12:48:55 +01001232 // Add the session listener so we can track the session progress
1233 // updates.
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001234 getServices().getCaptureSessionManager().addSessionListener(mSessionListener);
Angus Kong62848152013-11-08 17:25:29 -08001235 mFilmstripController = ((FilmstripView) findViewById(R.id.filmstrip_view)).getController();
Angus Kongfaaee012013-12-07 00:38:46 -08001236 mFilmstripController.setImageGap(
Doris Liu6432cd62013-06-13 17:20:31 -07001237 getResources().getDimensionPixelSize(R.dimen.camera_film_strip_gap));
Sascha Haeberlingf1f51862013-07-31 11:28:21 -07001238 mPanoramaViewHelper = new PanoramaViewHelper(this);
1239 mPanoramaViewHelper.onCreate();
Doris Liu6432cd62013-06-13 17:20:31 -07001240 // Set up the camera preview first so the preview shows up ASAP.
Sascha Haeberling846d3ab2014-02-04 12:48:55 +01001241 mDataAdapter = new CameraDataAdapter(mAppContext,
Angus Kong166e36f2013-12-03 08:54:42 -08001242 new ColorDrawable(getResources().getColor(R.color.photo_placeholder)));
Angus Konge2f4c032013-12-19 10:24:33 -08001243 mDataAdapter.setLocalDataListener(mLocalDataListener);
Angus Kongfaaee012013-12-07 00:38:46 -08001244
Sam Juddde3e9ab2014-03-17 13:07:22 -07001245 mPreloader = new Preloader<Integer, AsyncTask>(FILMSTRIP_PRELOAD_AHEAD_ITEMS, mDataAdapter,
1246 mDataAdapter);
1247
Spike Sprague0f3c4b42013-12-10 19:50:17 -08001248 mCameraAppUI.getFilmstripContentPanel().setFilmstripListener(mFilmstripListener);
Doris Liue7d7b9e2014-03-31 15:27:40 -07001249 if (mSettingsManager.getBoolean(SettingsManager.SETTING_SHOULD_SHOW_REFOCUS_VIEWER_CLING)) {
1250 mCameraAppUI.setupClingForViewer(CameraAppUI.BottomPanel.VIEWER_REFOCUS);
1251 }
Sascha Haeberling2654dd92013-08-28 15:28:57 -07001252
Sascha Haeberling846d3ab2014-02-04 12:48:55 +01001253 mLocationManager = new LocationManager(mAppContext);
Erin Dahlgren357b7672013-11-20 17:38:14 -08001254
Erin Dahlgren357b7672013-11-20 17:38:14 -08001255 mOrientationManager = new OrientationManagerImpl(this);
1256 mOrientationManager.addOnOrientationChangeListener(mMainHandler, this);
Erin Dahlgrenc120b0f2013-11-19 10:53:49 -08001257
Erin Dahlgren4e0a4642014-03-31 13:54:30 -07001258 setModuleFromModeIndex(getModeIndex());
Erin Dahlgrend8de0772014-02-03 10:12:27 -08001259 mCameraAppUI.prepareModuleUI();
Angus Kong13e87c42013-11-25 10:02:47 -08001260 mCurrentModule.init(this, isSecureCamera(), isCaptureIntent());
Sascha Haeberling37f36112013-08-06 14:31:52 -07001261
1262 if (!mSecureCamera) {
Angus Kong62848152013-11-08 17:25:29 -08001263 mFilmstripController.setDataAdapter(mDataAdapter);
Angus Konga7194602013-09-06 17:20:15 -07001264 if (!isCaptureIntent()) {
Sascha Haeberlingadde93f2014-03-31 16:58:11 -07001265 mDataAdapter.requestLoad(new Callback<Void>() {
1266 @Override
1267 public void onCallback(Void result) {
1268 fillTemporarySessions();
1269 }
1270 });
Angus Konga7194602013-09-06 17:20:15 -07001271 }
Sascha Haeberling37f36112013-08-06 14:31:52 -07001272 } else {
Sascha Haeberlinga5a08d72013-09-11 20:30:52 -07001273 // Put a lock placeholder as the last image by setting its date to
1274 // 0.
Sascha Haeberling37f36112013-08-06 14:31:52 -07001275 ImageView v = (ImageView) getLayoutInflater().inflate(
1276 R.layout.secure_album_placeholder, null);
Angus Kong690dc472013-09-21 14:48:51 -07001277 v.setOnClickListener(new View.OnClickListener() {
1278 @Override
1279 public void onClick(View view) {
Sascha Haeberlinga83ec8a2014-03-31 13:22:17 -07001280 UsageStatistics.instance().changeScreen(NavigationChange.Mode.GALLERY,
Andy Huibers10c58162014-03-29 14:06:54 -07001281 NavigationChange.InteractionCause.BUTTON);
Angus Kongd3de1712013-12-12 22:01:12 -08001282 startGallery();
Angus Kong690dc472013-09-21 14:48:51 -07001283 finish();
1284 }
1285 });
Alan Newberger62c6d862014-03-26 11:49:46 -07001286 v.setContentDescription(getString(R.string.accessibility_unlock_to_camera));
Sascha Haeberling37f36112013-08-06 14:31:52 -07001287 mDataAdapter = new FixedLastDataAdapter(
Sascha Haeberling846d3ab2014-02-04 12:48:55 +01001288 mAppContext,
Angus Kong166e36f2013-12-03 08:54:42 -08001289 mDataAdapter,
Angus Kongbd260692013-08-07 14:52:56 -07001290 new SimpleViewData(
Sascha Haeberling37f36112013-08-06 14:31:52 -07001291 v,
1292 v.getDrawable().getIntrinsicWidth(),
1293 v.getDrawable().getIntrinsicHeight(),
1294 0, 0));
1295 // Flush out all the original data.
1296 mDataAdapter.flush();
Angus Kong62848152013-11-08 17:25:29 -08001297 mFilmstripController.setDataAdapter(mDataAdapter);
Sascha Haeberling37f36112013-08-06 14:31:52 -07001298 }
Mangesh Ghiwarea5682ab2013-09-19 09:24:23 -07001299
1300 setupNfcBeamPush();
ztenghui064d6002013-09-05 15:47:58 -07001301
Doris Liu2b86d872013-09-26 15:23:41 -07001302 mLocalImagesObserver = new LocalMediaObserver();
1303 mLocalVideosObserver = new LocalMediaObserver();
ztenghui064d6002013-09-05 15:47:58 -07001304
1305 getContentResolver().registerContentObserver(
1306 MediaStore.Images.Media.EXTERNAL_CONTENT_URI, true,
1307 mLocalImagesObserver);
1308 getContentResolver().registerContentObserver(
1309 MediaStore.Video.Media.EXTERNAL_CONTENT_URI, true,
1310 mLocalVideosObserver);
Christian Wyglendowski6fe8c822013-11-26 14:16:04 -08001311 if (FeedbackHelper.feedbackAvailable()) {
Sascha Haeberling846d3ab2014-02-04 12:48:55 +01001312 mFeedbackHelper = new FeedbackHelper(mAppContext);
Christian Wyglendowski6fe8c822013-11-26 14:16:04 -08001313 }
Kevin Gabayan0aeb0c82014-04-08 11:12:05 -07001314 mMemoryManager = getServices().getMemoryManager();
Kevin Gabayan05ee74d2014-04-08 16:25:23 -07001315
1316 AsyncTask.THREAD_POOL_EXECUTOR.execute(new Runnable() {
1317 public void run() {
1318 HashMap memoryData = mMemoryManager.queryMemory();
1319 UsageStatistics.instance().reportMemoryConsumed(memoryData,
1320 MemoryQuery.REPORT_LABEL_LAUNCH);
1321 }
1322 });
Michael Kolb8872c232013-01-29 10:33:22 -08001323 }
1324
Sascha Haeberling2d11fcf2014-03-13 09:04:32 -07001325 /**
Erin Dahlgren4e0a4642014-03-31 13:54:30 -07001326 * Get the current mode index from the Intent or from persistent
1327 * settings.
1328 */
1329 public int getModeIndex() {
1330 int modeIndex = -1;
1331 int photoIndex = getResources().getInteger(R.integer.camera_mode_photo);
1332 int videoIndex = getResources().getInteger(R.integer.camera_mode_video);
1333 int gcamIndex = getResources().getInteger(R.integer.camera_mode_gcam);
1334 if (MediaStore.INTENT_ACTION_VIDEO_CAMERA.equals(getIntent().getAction())
1335 || MediaStore.ACTION_VIDEO_CAPTURE.equals(getIntent().getAction())) {
1336 modeIndex = videoIndex;
1337 } else if (MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA.equals(getIntent().getAction())
1338 || MediaStore.ACTION_IMAGE_CAPTURE.equals(getIntent().getAction())) {
1339 // TODO: synchronize mode options with photo module without losing
1340 // HDR+ preferences.
1341 modeIndex = photoIndex;
1342 } else if (MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE.equals(getIntent()
1343 .getAction())
1344 || MediaStore.ACTION_IMAGE_CAPTURE_SECURE.equals(getIntent().getAction())) {
1345 modeIndex = mSettingsManager.getInt(
1346 SettingsManager.SETTING_KEY_CAMERA_MODULE_LAST_USED_INDEX);
1347 } else {
1348 // If the activity has not been started using an explicit intent,
1349 // read the module index from the last time the user changed modes
1350 modeIndex = mSettingsManager.getInt(SettingsManager.SETTING_STARTUP_MODULE_INDEX);
1351 if ((modeIndex == gcamIndex &&
1352 !GcamHelper.hasGcamCapture()) || modeIndex < 0) {
1353 modeIndex = photoIndex;
1354 }
1355 }
1356 return modeIndex;
1357 }
1358
1359 /**
Sascha Haeberling2d11fcf2014-03-13 09:04:32 -07001360 * Call this whenever the mode drawer or filmstrip change the visibility
1361 * state.
1362 */
1363 private void updatePreviewVisibility() {
1364 if (mCurrentModule == null) {
1365 return;
1366 }
Sam Judd1b125322014-03-21 16:53:27 -07001367
1368 int visibility = getPreviewVisibility();
1369 updatePreviewRendering(visibility);
Alan Newbergerb6db6912014-03-26 14:51:12 -07001370 updateCaptureControls(visibility);
Sascha Haeberling2d11fcf2014-03-13 09:04:32 -07001371 mCurrentModule.onPreviewVisibilityChanged(visibility);
1372 }
1373
Alan Newbergerb6db6912014-03-26 14:51:12 -07001374 private void updateCaptureControls(int visibility) {
1375 if (visibility == ModuleController.VISIBILITY_HIDDEN) {
1376 mCameraAppUI.setIndicatorBottomBarWrapperVisible(false);
1377 } else {
1378 mCameraAppUI.setIndicatorBottomBarWrapperVisible(true);
1379 }
1380 }
1381
Sam Judd1b125322014-03-21 16:53:27 -07001382 private void updatePreviewRendering(int visibility) {
1383 if (visibility == ModuleController.VISIBILITY_HIDDEN) {
1384 mCameraAppUI.pausePreviewRendering();
1385 } else {
1386 mCameraAppUI.resumePreviewRendering();
1387 }
1388 }
1389
1390 private int getPreviewVisibility() {
1391 if (mFilmstripCoversPreview) {
1392 return ModuleController.VISIBILITY_HIDDEN;
1393 } else if (mModeListVisible){
1394 return ModuleController.VISIBILITY_COVERED;
1395 } else {
1396 return ModuleController.VISIBILITY_VISIBLE;
1397 }
1398 }
1399
Doris Liu6432cd62013-06-13 17:20:31 -07001400 private void setRotationAnimation() {
Michael Kolb08650182013-02-25 19:43:56 -08001401 int rotationAnimation = WindowManager.LayoutParams.ROTATION_ANIMATION_ROTATE;
Doris Liu6432cd62013-06-13 17:20:31 -07001402 rotationAnimation = WindowManager.LayoutParams.ROTATION_ANIMATION_CROSSFADE;
Michael Kolb08650182013-02-25 19:43:56 -08001403 Window win = getWindow();
1404 WindowManager.LayoutParams winParams = win.getAttributes();
1405 winParams.rotationAnimation = rotationAnimation;
1406 win.setAttributes(winParams);
1407 }
1408
Michael Kolb8872c232013-01-29 10:33:22 -08001409 @Override
Michael Kolb8872c232013-01-29 10:33:22 -08001410 public void onUserInteraction() {
1411 super.onUserInteraction();
Angus Kong13e87c42013-11-25 10:02:47 -08001412 if (!isFinishing()) {
1413 keepScreenOnForAWhile();
1414 }
Michael Kolb8872c232013-01-29 10:33:22 -08001415 }
1416
1417 @Override
Doris Liu742cd5b2013-09-12 16:17:43 -07001418 public boolean dispatchTouchEvent(MotionEvent ev) {
1419 boolean result = super.dispatchTouchEvent(ev);
1420 if (ev.getActionMasked() == MotionEvent.ACTION_DOWN) {
1421 // Real deletion is postponed until the next user interaction after
Sascha Haeberling846d3ab2014-02-04 12:48:55 +01001422 // the gesture that triggers deletion. Until real deletion is
1423 // performed, users can click the undo button to bring back the
1424 // image that they chose to delete.
Doris Liu742cd5b2013-09-12 16:17:43 -07001425 if (mPendingDeletion && !mIsUndoingDeletion) {
Angus Kong20fad242013-11-11 18:23:46 -08001426 performDeletion();
Doris Liu742cd5b2013-09-12 16:17:43 -07001427 }
1428 }
1429 return result;
1430 }
1431
1432 @Override
Doris Liu6432cd62013-06-13 17:20:31 -07001433 public void onPause() {
Erin Dahlgren5f38da82014-04-01 11:48:40 -07001434 CameraPerformanceTracker.onEvent(CameraPerformanceTracker.ACTIVITY_PAUSE);
1435
Erin Dahlgren4e0a4642014-03-31 13:54:30 -07001436 /*
1437 * Save the last module index after all secure camera and icon launches,
1438 * not just on mode switches.
1439 *
1440 * Right now we exclude capture intents from this logic, because we also
1441 * ignore the cross-Activity recovery logic in onStart for capture intents.
1442 */
1443 if (!isCaptureIntent()) {
1444 mSettingsManager.setInt(SettingsManager.SETTING_STARTUP_MODULE_INDEX,
1445 mCurrentModeIndex);
1446 }
1447
Erin Dahlgrenc120b0f2013-11-19 10:53:49 -08001448 mPaused = true;
Angus Kong50521172014-01-17 17:23:59 -08001449 mPeekAnimationHandler = null;
1450 mPeekAnimationThread.quitSafely();
1451 mPeekAnimationThread = null;
Erin Dahlgrenc120b0f2013-11-19 10:53:49 -08001452
Doris Liuf2c14332013-09-26 11:24:37 -07001453 // Delete photos that are pending deletion
1454 performDeletion();
Angus Kongc4e66562013-11-22 23:03:21 -08001455 mCurrentModule.pause();
Angus Kong9f1db522013-11-09 16:25:59 -08001456 mOrientationManager.pause();
Angus Kong20fad242013-11-11 18:23:46 -08001457 // Close the camera and wait for the operation done.
1458 mCameraController.closeCamera();
Alan Newberger04bd11c2014-01-28 18:09:30 -08001459 mPanoramaViewHelper.onPause();
Doris Liu2b86d872013-09-26 15:23:41 -07001460
Sam Juddaeed91f2014-03-13 11:40:10 -07001461 mLocalImagesObserver.setForegroundChangeListener(null);
Doris Liu2b86d872013-09-26 15:23:41 -07001462 mLocalImagesObserver.setActivityPaused(true);
1463 mLocalVideosObserver.setActivityPaused(true);
Sam Juddde3e9ab2014-03-17 13:07:22 -07001464 mPreloader.cancelAllLoads();
Angus Kong13e87c42013-11-25 10:02:47 -08001465 resetScreenOn();
Angus Kongc4e66562013-11-22 23:03:21 -08001466 super.onPause();
Doris Liu6432cd62013-06-13 17:20:31 -07001467 }
1468
1469 @Override
Sascha Haeberlingb7639c62013-09-09 14:42:43 -07001470 protected void onActivityResult(int requestCode, int resultCode, Intent data) {
ztenghui064d6002013-09-05 15:47:58 -07001471 if (requestCode == REQ_CODE_DONT_SWITCH_TO_PREVIEW) {
Sascha Haeberlingb7639c62013-09-09 14:42:43 -07001472 mResetToPreviewOnResume = false;
1473 } else {
1474 super.onActivityResult(requestCode, resultCode, data);
1475 }
1476 }
1477
1478 @Override
Doris Liu6432cd62013-06-13 17:20:31 -07001479 public void onResume() {
Doris Liu7cbecee2014-01-30 12:29:27 -08001480 CameraPerformanceTracker.onEvent(CameraPerformanceTracker.ACTIVITY_RESUME);
Andy Huiberseaaf2932014-04-28 13:18:31 -07001481 Log.v(TAG, "Build info: " + Build.DISPLAY);
Erin Dahlgrenc120b0f2013-11-19 10:53:49 -08001482
Erin Dahlgren5f38da82014-04-01 11:48:40 -07001483 mPaused = false;
Spike Spraguee6374b72014-04-25 17:24:32 -07001484 updateStorageSpaceAndHint(null);
Erin Dahlgren5f38da82014-04-01 11:48:40 -07001485
Angus Kong53ae0412013-12-01 23:21:49 -08001486 mLastLayoutOrientation = getResources().getConfiguration().orientation;
1487
Angus Kongce2b9492013-09-05 17:49:06 -07001488 // TODO: Handle this in OrientationManager.
Sascha Haeberlinga5a08d72013-09-11 20:30:52 -07001489 // Auto-rotate off
Doris Liu6432cd62013-06-13 17:20:31 -07001490 if (Settings.System.getInt(getContentResolver(),
Sascha Haeberlinga5a08d72013-09-11 20:30:52 -07001491 Settings.System.ACCELEROMETER_ROTATION, 0) == 0) {
Doris Liu6432cd62013-06-13 17:20:31 -07001492 setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
1493 mAutoRotateScreen = false;
1494 } else {
1495 setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR);
1496 mAutoRotateScreen = true;
1497 }
Seth Raphaelcbd82672013-11-05 10:12:36 -08001498
Andy Huibers10c58162014-03-29 14:06:54 -07001499 String action = getIntent().getAction();
1500 // Foreground event logging
1501 if (MediaStore.ACTION_VIDEO_CAPTURE.equals(action)) {
1502 UsageStatistics.instance().foregrounded(ForegroundSource.ACTION_VIDEO_CAPTURE,
1503 currentUserInterfaceMode());
1504 } else if (MediaStore.ACTION_IMAGE_CAPTURE.equals(action)) {
1505 UsageStatistics.instance().foregrounded(ForegroundSource.ACTION_IMAGE_CAPTURE,
1506 currentUserInterfaceMode());
1507 } else if (MediaStore.ACTION_IMAGE_CAPTURE_SECURE.equals(action) ||
1508 INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE.equals(action)) {
1509 // logged in onCreate()
1510 } else if (Intent.ACTION_MAIN.equals(action)) {
1511 UsageStatistics.instance().foregrounded(ForegroundSource.ACTION_MAIN,
1512 currentUserInterfaceMode());
1513 } else {
1514 UsageStatistics.instance().foregrounded(ForegroundSource.UNKNOWN_SOURCE,
1515 currentUserInterfaceMode());
Erin Dahlgrenf6edd532014-01-31 11:13:33 -08001516 }
Seth Raphaelcbd82672013-11-05 10:12:36 -08001517
Angus Kong6c0c7f12014-01-15 14:40:27 -08001518 Drawable galleryLogo;
1519 if (mSecureCamera) {
1520 mGalleryIntent = null;
1521 galleryLogo = null;
1522 } else {
Sascha Haeberling846d3ab2014-02-04 12:48:55 +01001523 mGalleryIntent = IntentHelper.getDefaultGalleryIntent(mAppContext);
1524 galleryLogo = IntentHelper.getGalleryIcon(mAppContext, mGalleryIntent);
Angus Kong6c0c7f12014-01-15 14:40:27 -08001525 }
1526 if (galleryLogo == null) {
1527 try {
1528 galleryLogo = getPackageManager().getActivityLogo(getComponentName());
1529 } catch (PackageManager.NameNotFoundException e) {
1530 Log.e(TAG, "Can't get the activity logo");
1531 }
1532 }
Angus Kong601c8c12014-02-21 10:01:58 -08001533 if (mGalleryIntent != null) {
1534 mActionBar.setDisplayUseLogoEnabled(true);
1535 }
Angus Kong6c0c7f12014-01-15 14:40:27 -08001536 mActionBar.setLogo(galleryLogo);
Angus Kong9f1db522013-11-09 16:25:59 -08001537 mOrientationManager.resume();
Doris Liu6432cd62013-06-13 17:20:31 -07001538 super.onResume();
Angus Kong50521172014-01-17 17:23:59 -08001539 mPeekAnimationThread = new HandlerThread("Peek animation");
1540 mPeekAnimationThread.start();
1541 mPeekAnimationHandler = new PeekAnimationHandler(mPeekAnimationThread.getLooper());
Erin Dahlgren1ca516f2014-03-28 12:44:04 -07001542
1543 mCurrentModule.hardResetSettings(mSettingsManager);
Angus Kongc4e66562013-11-22 23:03:21 -08001544 mCurrentModule.resume();
Andy Huibers10c58162014-03-29 14:06:54 -07001545 UsageStatistics.instance().changeScreen(currentUserInterfaceMode(),
1546 NavigationChange.InteractionCause.BUTTON);
Angus Kong6798c342013-07-16 15:14:58 -07001547 setSwipingEnabled(true);
Sascha Haeberlingb7639c62013-09-09 14:42:43 -07001548
Erin Dahlgren4e0a4642014-03-31 13:54:30 -07001549 if (!mResetToPreviewOnResume) {
Sascha Haeberling846d3ab2014-02-04 12:48:55 +01001550 LocalData data = mDataAdapter.getLocalData(mFilmstripController.getCurrentId());
Angus Kong2520b502014-01-10 17:45:27 -08001551 if (data != null) {
Angus Kong571a8c32014-03-13 12:53:03 -07001552 mDataAdapter.refresh(data.getUri());
Angus Kong2520b502014-01-10 17:45:27 -08001553 }
Sascha Haeberlingb7639c62013-09-09 14:42:43 -07001554 }
Angus Konge4002f32013-12-13 22:24:11 -08001555 // The share button might be disabled to avoid double tapping.
1556 mCameraAppUI.getFilmstripBottomControls().setShareEnabled(true);
Sascha Haeberlingb7639c62013-09-09 14:42:43 -07001557 // Default is showing the preview, unless disabled by explicitly
1558 // starting an activity we want to return from to the filmstrip rather
1559 // than the preview.
1560 mResetToPreviewOnResume = true;
ztenghui064d6002013-09-05 15:47:58 -07001561
Doris Liu2b86d872013-09-26 15:23:41 -07001562 if (mLocalVideosObserver.isMediaDataChangedDuringPause()
1563 || mLocalImagesObserver.isMediaDataChangedDuringPause()) {
Angus Kong2d5c7472013-10-12 23:48:46 -07001564 if (!mSecureCamera) {
1565 // If it's secure camera, requestLoad() should not be called
1566 // as it will load all the data.
Angus Kongb2510252013-12-10 22:58:15 -08001567 if (!mFilmstripVisible) {
Sascha Haeberlingadde93f2014-03-31 16:58:11 -07001568 mDataAdapter.requestLoad(new Callback<Void>() {
1569 @Override
1570 public void onCallback(Void result) {
1571 fillTemporarySessions();
1572 }
1573 });
Sam Juddaeed91f2014-03-13 11:40:10 -07001574 } else {
1575 mDataAdapter.requestLoadNewPhotos();
Angus Kongb2510252013-12-10 22:58:15 -08001576 }
Angus Kong2d5c7472013-10-12 23:48:46 -07001577 }
ztenghui064d6002013-09-05 15:47:58 -07001578 }
Doris Liu2b86d872013-09-26 15:23:41 -07001579 mLocalImagesObserver.setActivityPaused(false);
1580 mLocalVideosObserver.setActivityPaused(false);
Sam Judd6383d972014-03-18 16:00:32 -07001581 if (!mSecureCamera) {
1582 mLocalImagesObserver.setForegroundChangeListener(
1583 new LocalMediaObserver.ChangeListener() {
1584 @Override
1585 public void onChange() {
1586 mDataAdapter.requestLoadNewPhotos();
1587 }
1588 });
1589 }
Doris Liu70576b62013-11-14 20:30:33 -08001590
Angus Kong13e87c42013-11-25 10:02:47 -08001591 keepScreenOnForAWhile();
Sascha Haeberling20639e72014-01-07 13:31:19 -08001592
Sascha Haeberling39675162014-04-02 18:16:42 -07001593 // Lights-out mode at all times.
Sascha Haeberling099b49b2014-04-08 07:08:46 -07001594 final View rootView = findViewById(R.id.activity_root_view);
1595 mLightsOutRunnable.run();
1596 getWindow().getDecorView().setOnSystemUiVisibilityChangeListener(
1597 new OnSystemUiVisibilityChangeListener() {
1598 @Override
1599 public void onSystemUiVisibilityChange(int visibility) {
1600 mMainHandler.removeCallbacks(mLightsOutRunnable);
1601 mMainHandler.postDelayed(mLightsOutRunnable, LIGHTS_OUT_DELAY_MS);
1602 }
1603 });
Sascha Haeberling39675162014-04-02 18:16:42 -07001604
Alan Newberger04bd11c2014-01-28 18:09:30 -08001605 mPanoramaViewHelper.onResume();
Sascha Haeberling7190c6a2014-02-21 10:11:31 -08001606 ReleaseDialogHelper.showReleaseInfoDialogOnStart(this, mSettingsManager);
Sascha Haeberling91c25e32014-02-26 14:10:48 -08001607 syncLocationManagerSetting();
Sam Judd1b125322014-03-21 16:53:27 -07001608
1609 final int previewVisibility = getPreviewVisibility();
1610 updatePreviewRendering(previewVisibility);
Angus Kong6798c342013-07-16 15:14:58 -07001611 }
1612
Sascha Haeberlingadde93f2014-03-31 16:58:11 -07001613 private void fillTemporarySessions() {
1614 if (mSecureCamera) {
1615 return;
1616 }
1617 // There might be sessions still in flight (processed by our service).
1618 // Make sure they're added to the filmstrip.
1619 getServices().getCaptureSessionManager().fillTemporarySession(mSessionListener);
1620 }
1621
Angus Kong6798c342013-07-16 15:14:58 -07001622 @Override
1623 public void onStart() {
1624 super.onStart();
Sascha Haeberlingf1f51862013-07-31 11:28:21 -07001625 mPanoramaViewHelper.onStart();
Erin Dahlgren4e0a4642014-03-31 13:54:30 -07001626
1627 /*
1628 * If we're starting after launching a different Activity (lockscreen),
1629 * we need to use the last mode used in the other Activity, and
1630 * not the old one from this Activity.
1631 *
1632 * This needs to happen before CameraAppUI.resume() in order to set the
1633 * mode cover icon to the actual last mode used.
1634 *
1635 * Right now we exclude capture intents from this logic.
1636 */
1637 int modeIndex = getModeIndex();
1638 if (!isCaptureIntent() && mCurrentModeIndex != modeIndex) {
1639 onModeSelected(modeIndex);
1640 }
1641
Seth Raphael7dcf8b12014-03-11 16:44:25 -07001642 if (mResetToPreviewOnResume) {
1643 mCameraAppUI.resume();
1644 mResetToPreviewOnResume = false;
1645 }
Sascha Haeberlingf1f51862013-07-31 11:28:21 -07001646 }
1647
1648 @Override
1649 protected void onStop() {
Sascha Haeberlingf1f51862013-07-31 11:28:21 -07001650 mPanoramaViewHelper.onStop();
Christian Wyglendowski6fe8c822013-11-26 14:16:04 -08001651 if (mFeedbackHelper != null) {
1652 mFeedbackHelper.stopFeedback();
1653 }
Angus Kong0e57fc12013-11-18 13:21:07 -08001654
Kevin Gabayanffbc43c2013-12-09 11:41:50 -08001655 mLocationManager.disconnect();
Angus Kong0e57fc12013-11-18 13:21:07 -08001656 super.onStop();
Doris Liu6432cd62013-06-13 17:20:31 -07001657 }
1658
1659 @Override
1660 public void onDestroy() {
Sascha Haeberlinga5a08d72013-09-11 20:30:52 -07001661 if (mSecureCamera) {
1662 unregisterReceiver(mScreenOffReceiver);
1663 }
Sascha Haeberling846d3ab2014-02-04 12:48:55 +01001664 mActionBar.removeOnMenuVisibilityListener(this);
Erin Dahlgren1648c362014-01-06 15:06:04 -08001665 mSettingsManager.removeAllListeners();
Sascha Haeberling846d3ab2014-02-04 12:48:55 +01001666 mCameraController.removeCallbackReceiver();
ztenghui064d6002013-09-05 15:47:58 -07001667 getContentResolver().unregisterContentObserver(mLocalImagesObserver);
1668 getContentResolver().unregisterContentObserver(mLocalVideosObserver);
Sascha Haeberling846d3ab2014-02-04 12:48:55 +01001669 getServices().getCaptureSessionManager().removeSessionListener(mSessionListener);
1670 mCameraAppUI.onDestroy();
Doris Liu3cea8cc2014-03-25 17:59:05 -07001671 mModeListView.setVisibilityChangedListener(null);
Sascha Haeberling846d3ab2014-02-04 12:48:55 +01001672 mCameraController = null;
1673 mSettingsManager = null;
Sascha Haeberling846d3ab2014-02-04 12:48:55 +01001674 mCameraAppUI = null;
1675 mOrientationManager = null;
1676 mButtonManager = null;
Angus Kong62753ae2014-02-10 10:53:54 -08001677 CameraManagerFactory.recycle();
Doris Liu6432cd62013-06-13 17:20:31 -07001678 super.onDestroy();
1679 }
1680
1681 @Override
1682 public void onConfigurationChanged(Configuration config) {
1683 super.onConfigurationChanged(config);
Angus Kong166e36f2013-12-03 08:54:42 -08001684 Log.v(TAG, "onConfigurationChanged");
Angus Kong2f0e4a32013-12-03 10:02:35 -08001685 if (config.orientation == Configuration.ORIENTATION_UNDEFINED) {
1686 return;
1687 }
1688
Angus Kong53ae0412013-12-01 23:21:49 -08001689 if (mLastLayoutOrientation != config.orientation) {
1690 mLastLayoutOrientation = config.orientation;
Angus Kong2f0e4a32013-12-03 10:02:35 -08001691 mCurrentModule.onLayoutOrientationChanged(
1692 mLastLayoutOrientation == Configuration.ORIENTATION_LANDSCAPE);
Angus Kong53ae0412013-12-01 23:21:49 -08001693 }
Doris Liu6432cd62013-06-13 17:20:31 -07001694 }
1695
1696 @Override
1697 public boolean onKeyDown(int keyCode, KeyEvent event) {
Angus Kong8dcccb12014-01-02 16:00:49 -08001698 if (!mFilmstripVisible) {
Doris Liudba16ae2013-10-03 15:31:40 -07001699 if (mCurrentModule.onKeyDown(keyCode, event)) {
Sascha Haeberlinga5a08d72013-09-11 20:30:52 -07001700 return true;
1701 }
Doris Liudba16ae2013-10-03 15:31:40 -07001702 // Prevent software keyboard or voice search from showing up.
1703 if (keyCode == KeyEvent.KEYCODE_SEARCH
1704 || keyCode == KeyEvent.KEYCODE_MENU) {
1705 if (event.isLongPress()) {
1706 return true;
1707 }
1708 }
Doris Liu6432cd62013-06-13 17:20:31 -07001709 }
Doris Liu6432cd62013-06-13 17:20:31 -07001710
1711 return super.onKeyDown(keyCode, event);
1712 }
1713
1714 @Override
1715 public boolean onKeyUp(int keyCode, KeyEvent event) {
Erin Dahlgren15691af2014-03-14 14:10:57 -07001716 if (!mFilmstripVisible) {
1717 // If a module is in the middle of capture, it should
1718 // consume the key event.
1719 if (mCurrentModule.onKeyUp(keyCode, event)) {
1720 return true;
Alan Newberger623dd0c2014-03-24 15:55:23 -07001721 } else if (keyCode == KeyEvent.KEYCODE_MENU
1722 || keyCode == KeyEvent.KEYCODE_DPAD_LEFT) {
Erin Dahlgren15691af2014-03-14 14:10:57 -07001723 // Let the mode list view consume the event.
1724 mModeListView.onMenuPressed();
1725 return true;
Alan Newberger623dd0c2014-03-24 15:55:23 -07001726 } else if (keyCode == KeyEvent.KEYCODE_DPAD_RIGHT) {
1727 mCameraAppUI.showFilmstrip();
1728 return true;
Erin Dahlgren15691af2014-03-14 14:10:57 -07001729 }
Alan Newberger8099a372014-03-24 17:17:38 -07001730 } else {
1731 if (keyCode == KeyEvent.KEYCODE_DPAD_RIGHT) {
1732 mFilmstripController.goToNextItem();
1733 return true;
1734 } else if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT) {
1735 boolean wentToPrevious = mFilmstripController.goToPreviousItem();
1736 if (!wentToPrevious) {
1737 // at beginning of filmstrip, hide and go back to preview
1738 mCameraAppUI.hideFilmstrip();
1739 }
1740 return true;
1741 }
Sascha Haeberlinga5a08d72013-09-11 20:30:52 -07001742 }
Doris Liu6432cd62013-06-13 17:20:31 -07001743 return super.onKeyUp(keyCode, event);
1744 }
1745
Alan Newberger5f6b50d2013-08-30 15:19:48 -07001746 @Override
1747 public void onBackPressed() {
Angus Kong166e36f2013-12-03 08:54:42 -08001748 if (!mCameraAppUI.onBackPressed()) {
1749 if (!mCurrentModule.onBackPressed()) {
1750 super.onBackPressed();
1751 }
Alan Newberger5f6b50d2013-08-30 15:19:48 -07001752 }
1753 }
1754
Sascha Haeberlinga7cbfc02014-02-14 11:06:03 +01001755 @Override
Doris Liu6432cd62013-06-13 17:20:31 -07001756 public boolean isAutoRotateScreen() {
Sascha Haeberlinga7cbfc02014-02-14 11:06:03 +01001757 // TODO: Move to OrientationManager.
Doris Liu6432cd62013-06-13 17:20:31 -07001758 return mAutoRotateScreen;
1759 }
1760
Sascha Haeberlingd114a772014-02-28 21:27:27 -08001761 @Override
1762 public boolean onCreateOptionsMenu(Menu menu) {
1763 MenuInflater inflater = getMenuInflater();
1764 inflater.inflate(R.menu.filmstrip_menu, menu);
1765 mActionBarMenu = menu;
1766 return super.onCreateOptionsMenu(menu);
1767 }
1768
Angus Kong2dcc0a92013-09-25 13:00:08 -07001769 protected long getStorageSpaceBytes() {
Erin Dahlgrenc4fbb3d2014-04-01 15:11:34 -07001770 synchronized (mStorageSpaceLock) {
1771 return mStorageSpaceBytes;
1772 }
Doris Liu6432cd62013-06-13 17:20:31 -07001773 }
1774
Spike Spraguee6374b72014-04-25 17:24:32 -07001775 protected interface OnStorageUpdateDoneListener {
1776 public void onStorageUpdateDone(long bytes);
1777 }
1778
1779 protected void updateStorageSpaceAndHint(final OnStorageUpdateDoneListener callback) {
Erin Dahlgrenc4fbb3d2014-04-01 15:11:34 -07001780 /*
1781 * We execute disk operations on a background thread in order to
1782 * free up the UI thread. Synchronizing on the lock below ensures
1783 * that when getStorageSpaceBytes is called, the main thread waits
1784 * until this method has completed.
Spike Spraguee6374b72014-04-25 17:24:32 -07001785 *
1786 * However, .execute() does not ensure this execution block will be
1787 * run right away (.execute() schedules this AsyncTask for sometime
1788 * in the future. executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR)
1789 * tries to execute the task in parellel with other AsyncTasks, but
1790 * there's still no guarantee).
1791 * e.g. don't call this then immediately call getStorageSpaceBytes().
1792 * Instead, pass in an OnStorageUpdateDoneListener.
Erin Dahlgrenc4fbb3d2014-04-01 15:11:34 -07001793 */
Spike Spraguee6374b72014-04-25 17:24:32 -07001794 (new AsyncTask<Void, Void, Long>() {
Erin Dahlgrenc4fbb3d2014-04-01 15:11:34 -07001795 @Override
Spike Spraguee6374b72014-04-25 17:24:32 -07001796 protected Long doInBackground(Void ... arg) {
Erin Dahlgrenc4fbb3d2014-04-01 15:11:34 -07001797 synchronized (mStorageSpaceLock) {
1798 mStorageSpaceBytes = Storage.getAvailableSpace();
Spike Spraguee6374b72014-04-25 17:24:32 -07001799 return mStorageSpaceBytes;
Erin Dahlgrenc4fbb3d2014-04-01 15:11:34 -07001800 }
Erin Dahlgrenc4fbb3d2014-04-01 15:11:34 -07001801 }
1802
1803 @Override
Spike Spraguee6374b72014-04-25 17:24:32 -07001804 protected void onPostExecute(Long bytes) {
1805 updateStorageHint(bytes);
1806 if (callback != null) {
1807 callback.onStorageUpdateDone(bytes);
1808 }
Erin Dahlgrenc4fbb3d2014-04-01 15:11:34 -07001809 }
Spike Spraguee6374b72014-04-25 17:24:32 -07001810 }).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
Doris Liu6432cd62013-06-13 17:20:31 -07001811 }
1812
1813 protected void updateStorageHint(long storageSpace) {
1814 String message = null;
1815 if (storageSpace == Storage.UNAVAILABLE) {
1816 message = getString(R.string.no_storage);
1817 } else if (storageSpace == Storage.PREPARING) {
1818 message = getString(R.string.preparing_sd);
1819 } else if (storageSpace == Storage.UNKNOWN_SIZE) {
1820 message = getString(R.string.access_sd_fail);
Angus Kong2dcc0a92013-09-25 13:00:08 -07001821 } else if (storageSpace <= Storage.LOW_STORAGE_THRESHOLD_BYTES) {
Doris Liu6432cd62013-06-13 17:20:31 -07001822 message = getString(R.string.spaceIsLow_content);
1823 }
1824
1825 if (message != null) {
1826 if (mStorageHint == null) {
Sascha Haeberling846d3ab2014-02-04 12:48:55 +01001827 mStorageHint = OnScreenHint.makeText(mAppContext, message);
Doris Liu6432cd62013-06-13 17:20:31 -07001828 } else {
1829 mStorageHint.setText(message);
1830 }
1831 mStorageHint.show();
1832 } else if (mStorageHint != null) {
1833 mStorageHint.cancel();
1834 mStorageHint = null;
1835 }
1836 }
1837
1838 protected void setResultEx(int resultCode) {
1839 mResultCodeForTesting = resultCode;
1840 setResult(resultCode);
1841 }
1842
1843 protected void setResultEx(int resultCode, Intent data) {
1844 mResultCodeForTesting = resultCode;
1845 mResultDataForTesting = data;
1846 setResult(resultCode, data);
1847 }
1848
1849 public int getResultCode() {
1850 return mResultCodeForTesting;
1851 }
1852
1853 public Intent getResultData() {
1854 return mResultDataForTesting;
1855 }
1856
1857 public boolean isSecureCamera() {
1858 return mSecureCamera;
Michael Kolb8872c232013-01-29 10:33:22 -08001859 }
1860
1861 @Override
Erin Dahlgrenc120b0f2013-11-19 10:53:49 -08001862 public boolean isPaused() {
1863 return mPaused;
1864 }
1865
1866 @Override
Erin Dahlgren1ba90e32014-03-03 12:05:57 -08001867 public int getPreferredChildModeIndex(int modeIndex) {
1868 if (modeIndex == getResources().getInteger(R.integer.camera_mode_photo)) {
1869 boolean hdrPlusOn = mSettingsManager.isHdrPlusOn();
1870 if (hdrPlusOn && GcamHelper.hasGcamCapture()) {
1871 modeIndex = getResources().getInteger(R.integer.camera_mode_gcam);
1872 }
1873 }
1874 return modeIndex;
1875 }
1876
1877 @Override
Erin Dahlgrenc120b0f2013-11-19 10:53:49 -08001878 public void onModeSelected(int modeIndex) {
1879 if (mCurrentModeIndex == modeIndex) {
Sascha Haeberlinga5a08d72013-09-11 20:30:52 -07001880 return;
1881 }
Doris Liu6432cd62013-06-13 17:20:31 -07001882
Doris Liu7cbecee2014-01-30 12:29:27 -08001883 CameraPerformanceTracker.onEvent(CameraPerformanceTracker.MODE_SWITCH_START);
Doris Liucf8b6532014-01-15 19:17:38 -08001884 // Record last used camera mode for quick switching
1885 if (modeIndex == getResources().getInteger(R.integer.camera_mode_photo)
Erin Dahlgrena6587a12014-02-03 13:24:55 -08001886 || modeIndex == getResources().getInteger(R.integer.camera_mode_gcam)) {
Doris Liucf8b6532014-01-15 19:17:38 -08001887 mSettingsManager.setInt(SettingsManager.SETTING_KEY_CAMERA_MODULE_LAST_USED_INDEX,
1888 modeIndex);
1889 }
1890
Doris Liu6432cd62013-06-13 17:20:31 -07001891 closeModule(mCurrentModule);
Erin Dahlgrena340f072014-01-06 17:31:23 -08001892
Erin Dahlgren1ba90e32014-03-03 12:05:57 -08001893 // Select the correct module index from the mode switcher index.
1894 modeIndex = getPreferredChildModeIndex(modeIndex);
Erin Dahlgrenc120b0f2013-11-19 10:53:49 -08001895 setModuleFromModeIndex(modeIndex);
Doris Liuf55f3c42013-11-20 00:24:46 -08001896
Erin Dahlgrend8de0772014-02-03 10:12:27 -08001897 mCameraAppUI.resetBottomControls(mCurrentModule, modeIndex);
Erin Dahlgren5d187692014-02-25 19:16:12 -08001898 mCameraAppUI.addShutterListener(mCurrentModule);
Sascha Haeberling2654dd92013-08-28 15:28:57 -07001899 openModule(mCurrentModule);
1900 mCurrentModule.onOrientationChanged(mLastRawOrientation);
Sascha Haeberling2654dd92013-08-28 15:28:57 -07001901 // Store the module index so we can use it the next time the Camera
1902 // starts up.
Erin Dahlgren1ca516f2014-03-28 12:44:04 -07001903 mSettingsManager.setInt(SettingsManager.SETTING_STARTUP_MODULE_INDEX, modeIndex);
Erin Dahlgrenc120b0f2013-11-19 10:53:49 -08001904 }
1905
Sascha Haeberlingde303232014-02-07 02:30:53 +01001906 /**
1907 * Shows the settings dialog.
1908 */
Doris Liu9d264302014-02-11 10:41:40 -08001909 @Override
Doris Liuf55f3c42013-11-20 00:24:46 -08001910 public void onSettingsSelected() {
Andy Huibers10c58162014-03-29 14:06:54 -07001911 UsageStatistics.instance().controlUsed(
1912 eventprotos.ControlEvent.ControlType.OVERALL_SETTINGS);
Sascha Haeberlingde303232014-02-07 02:30:53 +01001913 Intent intent = new Intent(this, CameraSettingsActivity.class);
1914 startActivity(intent);
Sascha Haeberling2654dd92013-08-28 15:28:57 -07001915 }
1916
1917 /**
Sascha Haeberlinga5a08d72013-09-11 20:30:52 -07001918 * Sets the mCurrentModuleIndex, creates a new module instance for the given
1919 * index an sets it as mCurrentModule.
Sascha Haeberling2654dd92013-08-28 15:28:57 -07001920 */
Erin Dahlgrenc120b0f2013-11-19 10:53:49 -08001921 private void setModuleFromModeIndex(int modeIndex) {
1922 ModuleManagerImpl.ModuleAgent agent = mModuleManager.getModuleAgent(modeIndex);
Angus Kong20fad242013-11-11 18:23:46 -08001923 if (agent == null) {
1924 return;
Doris Liu6432cd62013-06-13 17:20:31 -07001925 }
Angus Kong20fad242013-11-11 18:23:46 -08001926 if (!agent.requestAppForCamera()) {
1927 mCameraController.closeCamera();
1928 }
Erin Dahlgrenc120b0f2013-11-19 10:53:49 -08001929 mCurrentModeIndex = agent.getModuleId();
Sascha Haeberling846d3ab2014-02-04 12:48:55 +01001930 mCurrentModule = (CameraModule) agent.createModule(this);
Michael Kolb8872c232013-01-29 10:33:22 -08001931 }
1932
Erin Dahlgrenc120b0f2013-11-19 10:53:49 -08001933 @Override
1934 public SettingsManager getSettingsManager() {
1935 return mSettingsManager;
1936 }
1937
Angus Kongc4e66562013-11-22 23:03:21 -08001938 @Override
1939 public CameraServices getServices() {
1940 return (CameraServices) getApplication();
1941 }
1942
Erin Dahlgrenf63967a2014-01-02 13:57:43 -08001943 public List<String> getSupportedModeNames() {
1944 List<Integer> indices = mModuleManager.getSupportedModeIndexList();
1945 List<String> supported = new ArrayList<String>();
1946
1947 for (Integer modeIndex : indices) {
Sascha Haeberling846d3ab2014-02-04 12:48:55 +01001948 String name = CameraUtil.getCameraModeText(modeIndex, mAppContext);
Erin Dahlgrenf63967a2014-01-02 13:57:43 -08001949 if (name != null && !name.equals("")) {
1950 supported.add(name);
1951 }
1952 }
1953 return supported;
1954 }
1955
Erin Dahlgren18484942014-01-07 11:46:57 -08001956 @Override
Erin Dahlgren18e2ef62013-12-05 14:53:38 -08001957 public ButtonManager getButtonManager() {
Erin Dahlgren8a2933b2013-12-06 12:07:33 -08001958 if (mButtonManager == null) {
1959 mButtonManager = new ButtonManager(this);
1960 }
1961 return mButtonManager;
Erin Dahlgren18e2ef62013-12-05 14:53:38 -08001962 }
1963
Sascha Haeberling88ef7662013-08-15 17:19:22 -07001964 /**
Sascha Haeberling846d3ab2014-02-04 12:48:55 +01001965 * Creates an AlertDialog appropriate for choosing whether to enable
1966 * location on the first run of the app.
Erin Dahlgren491c6282013-11-25 13:22:07 -08001967 */
1968 public AlertDialog getFirstTimeLocationAlert() {
Sascha Haeberlingf526f2f2014-02-05 22:06:27 +01001969 AlertDialog.Builder builder = new AlertDialog.Builder(this);
Sascha Haeberlingde303232014-02-07 02:30:53 +01001970 builder = SettingsUtil.getFirstTimeLocationAlertBuilder(builder, new Callback<Boolean>() {
1971 @Override
1972 public void onCallback(Boolean locationOn) {
1973 mSettingsManager.setLocation(locationOn, mLocationManager);
1974 }
1975 });
Erin Dahlgren491c6282013-11-25 13:22:07 -08001976 if (builder != null) {
1977 return builder.create();
1978 } else {
1979 return null;
1980 }
1981 }
1982
1983 /**
Sascha Haeberlinge8959e72014-01-31 15:21:02 +01001984 * Launches an ACTION_EDIT intent for the given local data item. If
1985 * 'withTinyPlanet' is set, this will show a disambig dialog first to let
1986 * the user start either the tiny planet editor or another photo edior.
1987 *
1988 * @param data The data item to edit.
Sascha Haeberling88ef7662013-08-15 17:19:22 -07001989 */
1990 public void launchEditor(LocalData data) {
1991 Intent intent = new Intent(Intent.ACTION_EDIT)
Angus Kong571a8c32014-03-13 12:53:03 -07001992 .setDataAndType(data.getUri(), data.getMimeType())
Sascha Haeberling88ef7662013-08-15 17:19:22 -07001993 .setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
Erin Dahlgren05a04922013-11-07 11:35:10 -08001994 try {
Angus Kong0eaf0162013-12-16 15:53:30 -08001995 launchActivityByIntent(intent);
Erin Dahlgren05a04922013-11-07 11:35:10 -08001996 } catch (ActivityNotFoundException e) {
Angus Kong0eaf0162013-12-16 15:53:30 -08001997 launchActivityByIntent(Intent.createChooser(intent, null));
Erin Dahlgren05a04922013-11-07 11:35:10 -08001998 }
Sascha Haeberling88ef7662013-08-15 17:19:22 -07001999 }
2000
Sascha Haeberlinge8959e72014-01-31 15:21:02 +01002001 @Override
2002 public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
2003 super.onCreateContextMenu(menu, v, menuInfo);
2004
2005 MenuInflater inflater = getMenuInflater();
2006 inflater.inflate(R.menu.filmstrip_context_menu, menu);
2007 }
2008
2009 @Override
2010 public boolean onContextItemSelected(MenuItem item) {
Sascha Haeberling846d3ab2014-02-04 12:48:55 +01002011 switch (item.getItemId()) {
Sascha Haeberlinge8959e72014-01-31 15:21:02 +01002012 case R.id.tiny_planet_editor:
2013 mMyFilmstripBottomControlListener.onTinyPlanet();
2014 return true;
2015 case R.id.photo_editor:
2016 mMyFilmstripBottomControlListener.onEdit();
2017 return true;
2018 }
2019 return false;
2020 }
2021
Sascha Haeberlinga5a08d72013-09-11 20:30:52 -07002022 /**
2023 * Launch the tiny planet editor.
2024 *
Angus Kong20fad242013-11-11 18:23:46 -08002025 * @param data The data must be a 360 degree stereographically mapped
Sascha Haeberling846d3ab2014-02-04 12:48:55 +01002026 * panoramic image. It will not be modified, instead a new item
2027 * with the result will be added to the filmstrip.
Sascha Haeberlinga5a08d72013-09-11 20:30:52 -07002028 */
2029 public void launchTinyPlanetEditor(LocalData data) {
2030 TinyPlanetFragment fragment = new TinyPlanetFragment();
2031 Bundle bundle = new Bundle();
Angus Kong571a8c32014-03-13 12:53:03 -07002032 bundle.putString(TinyPlanetFragment.ARGUMENT_URI, data.getUri().toString());
Sascha Haeberlinga5a08d72013-09-11 20:30:52 -07002033 bundle.putString(TinyPlanetFragment.ARGUMENT_TITLE, data.getTitle());
2034 fragment.setArguments(bundle);
2035 fragment.show(getFragmentManager(), "tiny_planet");
2036 }
2037
Andy Huibers10c58162014-03-29 14:06:54 -07002038 /**
2039 * Returns what UI mode (capture mode or filmstrip) we are in.
2040 * Returned number one of {@link com.google.common.logging.eventprotos.NavigationChange.Mode}
2041 */
2042 private int currentUserInterfaceMode() {
2043 int mode = NavigationChange.Mode.UNKNOWN_MODE;
2044 if (mCurrentModeIndex == getResources().getInteger(R.integer.camera_mode_photo)) {
2045 mode = NavigationChange.Mode.PHOTO_CAPTURE;
2046 }
2047 if (mCurrentModeIndex == getResources().getInteger(R.integer.camera_mode_video)) {
2048 mode = NavigationChange.Mode.VIDEO_CAPTURE;
2049 }
2050 if (mCurrentModeIndex == getResources().getInteger(R.integer.camera_mode_refocus)) {
2051 mode = NavigationChange.Mode.LENS_BLUR;
2052 }
2053 if (mCurrentModeIndex == getResources().getInteger(R.integer.camera_mode_gcam)) {
2054 mode = NavigationChange.Mode.HDR_PLUS;
2055 }
2056 if (mCurrentModeIndex == getResources().getInteger(R.integer.camera_mode_photosphere)) {
2057 mode = NavigationChange.Mode.PHOTO_SPHERE;
2058 }
2059 if (mCurrentModeIndex == getResources().getInteger(R.integer.camera_mode_panorama)) {
2060 mode = NavigationChange.Mode.PANORAMA;
2061 }
2062 if (mFilmstripVisible) {
2063 mode = NavigationChange.Mode.FILMSTRIP;
2064 }
2065 return mode;
2066 }
2067
Erin Dahlgrencb99b3d2014-01-07 17:16:20 -08002068 private void openModule(CameraModule module) {
Angus Kong13e87c42013-11-25 10:02:47 -08002069 module.init(this, isSecureCamera(), isCaptureIntent());
Erin Dahlgren1ca516f2014-03-28 12:44:04 -07002070 module.hardResetSettings(mSettingsManager);
Angus Kongc4e66562013-11-22 23:03:21 -08002071 module.resume();
Andy Huibers10c58162014-03-29 14:06:54 -07002072 UsageStatistics.instance().changeScreen(currentUserInterfaceMode(),
2073 NavigationChange.InteractionCause.BUTTON);
Sascha Haeberling2d11fcf2014-03-13 09:04:32 -07002074 updatePreviewVisibility();
Doris Liu6432cd62013-06-13 17:20:31 -07002075 }
2076
2077 private void closeModule(CameraModule module) {
Angus Kongc4e66562013-11-22 23:03:21 -08002078 module.pause();
Erin Dahlgren5d187692014-02-25 19:16:12 -08002079 mCameraAppUI.clearModuleUI();
Angus Kong653c43b2013-08-21 18:28:43 -07002080 }
2081
Doris Liu742cd5b2013-09-12 16:17:43 -07002082 private void performDeletion() {
2083 if (!mPendingDeletion) {
2084 return;
2085 }
2086 hideUndoDeletionBar(false);
Sascha Haeberling44c1afb2013-12-20 11:59:35 -08002087 mDataAdapter.executeDeletion();
Doris Liu742cd5b2013-09-12 16:17:43 -07002088 }
2089
2090 public void showUndoDeletionBar() {
2091 if (mPendingDeletion) {
2092 performDeletion();
2093 }
2094 Log.v(TAG, "showing undo bar");
2095 mPendingDeletion = true;
Angus Kong653c43b2013-08-21 18:28:43 -07002096 if (mUndoDeletionBar == null) {
Angus Kong20fad242013-11-11 18:23:46 -08002097 ViewGroup v = (ViewGroup) getLayoutInflater().inflate(R.layout.undo_bar,
2098 mAboveFilmstripControlLayout, true);
Angus Kong653c43b2013-08-21 18:28:43 -07002099 mUndoDeletionBar = (ViewGroup) v.findViewById(R.id.camera_undo_deletion_bar);
2100 View button = mUndoDeletionBar.findViewById(R.id.camera_undo_deletion_button);
2101 button.setOnClickListener(new View.OnClickListener() {
2102 @Override
2103 public void onClick(View view) {
2104 mDataAdapter.undoDataRemoval();
Doris Liu742cd5b2013-09-12 16:17:43 -07002105 hideUndoDeletionBar(true);
2106 }
2107 });
2108 // Setting undo bar clickable to avoid touch events going through
2109 // the bar to the buttons (eg. edit button, etc) underneath the bar.
2110 mUndoDeletionBar.setClickable(true);
2111 // When there is user interaction going on with the undo button, we
2112 // do not want to hide the undo bar.
2113 button.setOnTouchListener(new View.OnTouchListener() {
2114 @Override
2115 public boolean onTouch(View v, MotionEvent event) {
2116 if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
2117 mIsUndoingDeletion = true;
2118 } else if (event.getActionMasked() == MotionEvent.ACTION_UP) {
Angus Kong20fad242013-11-11 18:23:46 -08002119 mIsUndoingDeletion = false;
Doris Liu742cd5b2013-09-12 16:17:43 -07002120 }
2121 return false;
Angus Kong653c43b2013-08-21 18:28:43 -07002122 }
2123 });
2124 }
2125 mUndoDeletionBar.setAlpha(0f);
2126 mUndoDeletionBar.setVisibility(View.VISIBLE);
Doris Liu742cd5b2013-09-12 16:17:43 -07002127 mUndoDeletionBar.animate().setDuration(200).alpha(1f).setListener(null).start();
Angus Kong653c43b2013-08-21 18:28:43 -07002128 }
2129
Doris Liu742cd5b2013-09-12 16:17:43 -07002130 private void hideUndoDeletionBar(boolean withAnimation) {
Angus Kong653c43b2013-08-21 18:28:43 -07002131 Log.v(TAG, "Hiding undo deletion bar");
Doris Liu742cd5b2013-09-12 16:17:43 -07002132 mPendingDeletion = false;
Angus Kong653c43b2013-08-21 18:28:43 -07002133 if (mUndoDeletionBar != null) {
Doris Liu742cd5b2013-09-12 16:17:43 -07002134 if (withAnimation) {
Angus Kong20fad242013-11-11 18:23:46 -08002135 mUndoDeletionBar.animate().setDuration(200).alpha(0f)
Doris Liu742cd5b2013-09-12 16:17:43 -07002136 .setListener(new Animator.AnimatorListener() {
2137 @Override
2138 public void onAnimationStart(Animator animation) {
2139 // Do nothing.
2140 }
2141
2142 @Override
2143 public void onAnimationEnd(Animator animation) {
2144 mUndoDeletionBar.setVisibility(View.GONE);
2145 }
2146
2147 @Override
2148 public void onAnimationCancel(Animator animation) {
2149 // Do nothing.
2150 }
2151
2152 @Override
2153 public void onAnimationRepeat(Animator animation) {
2154 // Do nothing.
2155 }
Angus Kong20fad242013-11-11 18:23:46 -08002156 }).start();
Doris Liu742cd5b2013-09-12 16:17:43 -07002157 } else {
2158 mUndoDeletionBar.setVisibility(View.GONE);
2159 }
Angus Kong653c43b2013-08-21 18:28:43 -07002160 }
Michael Kolb8872c232013-01-29 10:33:22 -08002161 }
2162
2163 @Override
Angus Kong9f1db522013-11-09 16:25:59 -08002164 public void onOrientationChanged(int orientation) {
2165 // We keep the last known orientation. So if the user first orient
2166 // the camera then point the camera to floor or sky, we still have
2167 // the correct orientation.
2168 if (orientation == OrientationManager.ORIENTATION_UNKNOWN) {
2169 return;
2170 }
2171 mLastRawOrientation = orientation;
2172 if (mCurrentModule != null) {
2173 mCurrentModule.onOrientationChanged(orientation);
2174 }
2175 }
2176
Angus Konga7194602013-09-06 17:20:15 -07002177 /**
Sascha Haeberlinga5a08d72013-09-11 20:30:52 -07002178 * Enable/disable swipe-to-filmstrip. Will always disable swipe if in
2179 * capture intent.
Angus Konga7194602013-09-06 17:20:15 -07002180 *
2181 * @param enable {@code true} to enable swipe.
2182 */
Doris Liu6432cd62013-06-13 17:20:31 -07002183 public void setSwipingEnabled(boolean enable) {
Angus Kong166e36f2013-12-03 08:54:42 -08002184 // TODO: Bring back the functionality.
Angus Konga7194602013-09-06 17:20:15 -07002185 if (isCaptureIntent()) {
Sascha Haeberling846d3ab2014-02-04 12:48:55 +01002186 // lockPreview(true);
Angus Konga7194602013-09-06 17:20:15 -07002187 } else {
Sascha Haeberling846d3ab2014-02-04 12:48:55 +01002188 // lockPreview(!enable);
Angus Konga7194602013-09-06 17:20:15 -07002189 }
Michael Kolb8872c232013-01-29 10:33:22 -08002190 }
2191
2192 // Accessor methods for getting latency times used in performance testing
Kevin Gabayana0e83472014-01-15 15:21:13 -08002193 public long getFirstPreviewTime() {
2194 if (mCurrentModule instanceof PhotoModule) {
2195 long coverHiddenTime = getCameraAppUI().getCoverHiddenTime();
2196 if (coverHiddenTime != -1) {
2197 return coverHiddenTime - mOnCreateTime;
2198 }
2199 }
2200 return -1;
2201 }
2202
Michael Kolb8872c232013-01-29 10:33:22 -08002203 public long getAutoFocusTime() {
2204 return (mCurrentModule instanceof PhotoModule) ?
2205 ((PhotoModule) mCurrentModule).mAutoFocusTime : -1;
2206 }
2207
2208 public long getShutterLag() {
2209 return (mCurrentModule instanceof PhotoModule) ?
2210 ((PhotoModule) mCurrentModule).mShutterLag : -1;
2211 }
2212
2213 public long getShutterToPictureDisplayedTime() {
2214 return (mCurrentModule instanceof PhotoModule) ?
2215 ((PhotoModule) mCurrentModule).mShutterToPictureDisplayedTime : -1;
2216 }
2217
2218 public long getPictureDisplayedToJpegCallbackTime() {
2219 return (mCurrentModule instanceof PhotoModule) ?
2220 ((PhotoModule) mCurrentModule).mPictureDisplayedToJpegCallbackTime : -1;
2221 }
2222
2223 public long getJpegCallbackFinishTime() {
2224 return (mCurrentModule instanceof PhotoModule) ?
2225 ((PhotoModule) mCurrentModule).mJpegCallbackFinishTime : -1;
2226 }
2227
2228 public long getCaptureStartTime() {
2229 return (mCurrentModule instanceof PhotoModule) ?
2230 ((PhotoModule) mCurrentModule).mCaptureStartTime : -1;
2231 }
2232
2233 public boolean isRecording() {
2234 return (mCurrentModule instanceof VideoModule) ?
2235 ((VideoModule) mCurrentModule).isRecording() : false;
2236 }
Angus Kong4f795b82013-09-16 14:25:35 -07002237
Angus Kong62848152013-11-08 17:25:29 -08002238 public CameraManager.CameraOpenCallback getCameraOpenErrorCallback() {
Angus Kong20fad242013-11-11 18:23:46 -08002239 return mCameraController;
Angus Kong4f795b82013-09-16 14:25:35 -07002240 }
Ruben Brunkd217ed02013-10-08 23:31:13 -07002241
2242 // For debugging purposes only.
2243 public CameraModule getCurrentModule() {
2244 return mCurrentModule;
2245 }
Angus Kong13e87c42013-11-25 10:02:47 -08002246
Sascha Haeberlingc813ce12014-03-10 15:35:07 -07002247 @Override
2248 public void showTutorial(AbstractTutorialOverlay tutorial) {
2249 mCameraAppUI.showTutorial(tutorial, getLayoutInflater());
2250 }
2251
Sascha Haeberlingde303232014-02-07 02:30:53 +01002252 /**
2253 * Reads the current location recording settings and passes it on to the
2254 * location manager.
2255 */
2256 public void syncLocationManagerSetting() {
2257 mSettingsManager.syncLocationManager(mLocationManager);
2258 }
2259
Angus Kong13e87c42013-11-25 10:02:47 -08002260 private void keepScreenOnForAWhile() {
2261 if (mKeepScreenOn) {
2262 return;
2263 }
2264 mMainHandler.removeMessages(MSG_CLEAR_SCREEN_ON_FLAG);
2265 getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
2266 mMainHandler.sendEmptyMessageDelayed(MSG_CLEAR_SCREEN_ON_FLAG, SCREEN_DELAY_MS);
2267 }
2268
2269 private void resetScreenOn() {
2270 mKeepScreenOn = false;
2271 mMainHandler.removeMessages(MSG_CLEAR_SCREEN_ON_FLAG);
2272 getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
2273 }
Angus Kongb2510252013-12-10 22:58:15 -08002274
Angus Kong6c0c7f12014-01-15 14:40:27 -08002275 /**
2276 * @return {@code true} if the Gallery is launched successfully.
2277 */
2278 private boolean startGallery() {
2279 if (mGalleryIntent == null) {
2280 return false;
2281 }
Angus Kongd3de1712013-12-12 22:01:12 -08002282 try {
Sascha Haeberlinga83ec8a2014-03-31 13:22:17 -07002283 UsageStatistics.instance().changeScreen(NavigationChange.Mode.GALLERY,
Andy Huibers10c58162014-03-29 14:06:54 -07002284 NavigationChange.InteractionCause.BUTTON);
Alan Newberger80461c22014-02-03 15:03:26 -08002285 Intent startGalleryIntent = new Intent(mGalleryIntent);
2286 int currentDataId = mFilmstripController.getCurrentId();
2287 LocalData currentLocalData = mDataAdapter.getLocalData(currentDataId);
2288 if (currentLocalData != null) {
Angus Kong571a8c32014-03-13 12:53:03 -07002289 GalleryHelper.setContentUri(startGalleryIntent, currentLocalData.getUri());
Alan Newberger80461c22014-02-03 15:03:26 -08002290 }
2291 launchActivityByIntent(startGalleryIntent);
Angus Kongd3de1712013-12-12 22:01:12 -08002292 } catch (ActivityNotFoundException e) {
2293 Log.w(TAG, "Failed to launch gallery activity, closing");
2294 }
Angus Kong6c0c7f12014-01-15 14:40:27 -08002295 return false;
Angus Kongd3de1712013-12-12 22:01:12 -08002296 }
2297
Angus Kong662fbf42013-12-12 13:22:03 -08002298 private void setNfcBeamPushUriFromData(LocalData data) {
Angus Kong571a8c32014-03-13 12:53:03 -07002299 final Uri uri = data.getUri();
Angus Kong662fbf42013-12-12 13:22:03 -08002300 if (uri != Uri.EMPTY) {
2301 mNfcPushUris[0] = uri;
2302 } else {
2303 mNfcPushUris[0] = null;
2304 }
2305 }
2306
Angus Kongb2510252013-12-10 22:58:15 -08002307 /**
Sascha Haeberlingd114a772014-02-28 21:27:27 -08002308 * Updates the visibility of the filmstrip bottom controls and action bar.
Angus Kongb2510252013-12-10 22:58:15 -08002309 */
2310 private void updateUiByData(final int dataId) {
Angus Kongb2510252013-12-10 22:58:15 -08002311 final LocalData currentData = mDataAdapter.getLocalData(dataId);
2312 if (currentData == null) {
2313 Log.w(TAG, "Current data ID not found.");
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08002314 hideSessionProgress();
Angus Kongb2510252013-12-10 22:58:15 -08002315 return;
2316 }
Sascha Haeberlingd114a772014-02-28 21:27:27 -08002317 updateActionBarMenu(currentData);
Angus Kongb2510252013-12-10 22:58:15 -08002318
Angus Kong001dc312014-02-27 16:58:11 -08002319 /* Bottom controls. */
2320 updateBottomControlsByData(currentData);
2321
2322 if (isSecureCamera()) {
2323 // We cannot show buttons in secure camera since go to other
2324 // activities might create a security hole.
2325 mCameraAppUI.getFilmstripBottomControls().hideControls();
2326 return;
2327 }
2328
2329
Angus Kong662fbf42013-12-12 13:22:03 -08002330 setNfcBeamPushUriFromData(currentData);
2331
Angus Konge2f4c032013-12-19 10:24:33 -08002332 if (!mDataAdapter.isMetadataUpdated(dataId)) {
Sascha Haeberling44c1afb2013-12-20 11:59:35 -08002333 mDataAdapter.updateMetadata(dataId);
Angus Konge2f4c032013-12-19 10:24:33 -08002334 }
2335 }
2336
2337 /**
2338 * Updates the bottom controls based on the data.
2339 */
2340 private void updateBottomControlsByData(final LocalData currentData) {
2341
Angus Kong7ae25c22014-02-25 10:37:39 -08002342 final CameraAppUI.BottomPanel filmstripBottomPanel =
Angus Kongb2510252013-12-10 22:58:15 -08002343 mCameraAppUI.getFilmstripBottomControls();
Angus Kong001dc312014-02-27 16:58:11 -08002344 filmstripBottomPanel.showControls();
Angus Kong7ae25c22014-02-25 10:37:39 -08002345 filmstripBottomPanel.setEditButtonVisibility(
Angus Kong740cbee2013-12-11 15:46:16 -08002346 currentData.isDataActionSupported(LocalData.DATA_ACTION_EDIT));
Angus Kong7ae25c22014-02-25 10:37:39 -08002347 filmstripBottomPanel.setShareButtonVisibility(
Angus Konge0aff892013-12-11 20:51:01 -08002348 currentData.isDataActionSupported(LocalData.DATA_ACTION_SHARE));
Angus Kong7ae25c22014-02-25 10:37:39 -08002349 filmstripBottomPanel.setDeleteButtonVisibility(
Angus Konge0aff892013-12-11 20:51:01 -08002350 currentData.isDataActionSupported(LocalData.DATA_ACTION_DELETE));
Angus Kongb2510252013-12-10 22:58:15 -08002351
2352 /* Progress bar */
2353
Angus Kong571a8c32014-03-13 12:53:03 -07002354 Uri contentUri = currentData.getUri();
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08002355 CaptureSessionManager sessionManager = getServices()
2356 .getCaptureSessionManager();
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08002357
Sascha Haeberling597c1a02014-03-06 11:46:06 -08002358 if (sessionManager.hasErrorMessage(contentUri)) {
2359 showProcessError(sessionManager.getErrorMesage(contentUri));
Angus Kongb2510252013-12-10 22:58:15 -08002360 } else {
Sascha Haeberling597c1a02014-03-06 11:46:06 -08002361 filmstripBottomPanel.hideProgressError();
Seth Raphaelcc79da22014-03-20 16:47:53 -07002362 CaptureSession session = sessionManager.getSession(contentUri);
Sascha Haeberling597c1a02014-03-06 11:46:06 -08002363
Seth Raphaelcc79da22014-03-20 16:47:53 -07002364 if (session != null) {
2365 int sessionProgress = session.getProgress();
2366
2367 if (sessionProgress < 0) {
2368 hideSessionProgress();
2369 } else {
2370 CharSequence progressMessage = session.getProgressMessage();
2371 showSessionProgress(progressMessage);
2372 updateSessionProgress(sessionProgress);
2373 }
Sascha Haeberling597c1a02014-03-06 11:46:06 -08002374 } else {
Seth Raphaelcc79da22014-03-20 16:47:53 -07002375 hideSessionProgress();
Sascha Haeberling597c1a02014-03-06 11:46:06 -08002376 }
Angus Kongb2510252013-12-10 22:58:15 -08002377 }
2378
2379 /* View button */
2380
2381 // We need to add this to a separate DB.
Angus Kong8a2350a2013-12-16 15:02:34 -08002382 final int viewButtonVisibility;
Sascha Haeberling7190c6a2014-02-21 10:11:31 -08002383 if (PanoramaMetadataLoader.isPanoramaAndUseViewer(currentData)) {
Angus Kong7ae25c22014-02-25 10:37:39 -08002384 viewButtonVisibility = CameraAppUI.BottomPanel.VIEWER_PHOTO_SPHERE;
Angus Kong8a2350a2013-12-16 15:02:34 -08002385 } else if (RgbzMetadataLoader.hasRGBZData(currentData)) {
Angus Kong7ae25c22014-02-25 10:37:39 -08002386 viewButtonVisibility = CameraAppUI.BottomPanel.VIEWER_REFOCUS;
Angus Kong8a2350a2013-12-16 15:02:34 -08002387 } else {
Angus Kong7ae25c22014-02-25 10:37:39 -08002388 viewButtonVisibility = CameraAppUI.BottomPanel.VIEWER_NONE;
Angus Kong8a2350a2013-12-16 15:02:34 -08002389 }
Angus Kongb2510252013-12-10 22:58:15 -08002390
Angus Kong7ae25c22014-02-25 10:37:39 -08002391 filmstripBottomPanel.setTinyPlanetEnabled(
Angus Kong8a2350a2013-12-16 15:02:34 -08002392 PanoramaMetadataLoader.isPanorama360(currentData));
Angus Kong7ae25c22014-02-25 10:37:39 -08002393 filmstripBottomPanel.setViewerButtonVisibility(viewButtonVisibility);
Angus Kongb2510252013-12-10 22:58:15 -08002394 }
Angus Kong50521172014-01-17 17:23:59 -08002395
2396 private class PeekAnimationHandler extends Handler {
2397 private class DataAndCallback {
2398 LocalData mData;
2399 com.android.camera.util.Callback<Bitmap> mCallback;
2400
2401 public DataAndCallback(LocalData data, com.android.camera.util.Callback<Bitmap>
2402 callback) {
2403 mData = data;
2404 mCallback = callback;
2405 }
2406 }
2407
2408 public PeekAnimationHandler(Looper looper) {
2409 super(looper);
2410 }
2411
2412 /**
2413 * Starts the animation decoding job and posts a {@code Runnable} back
2414 * when when the decoding is done.
2415 *
2416 * @param data The data item to decode the thumbnail for.
2417 * @param callback {@link com.android.camera.util.Callback} after the
2418 * decoding is done.
2419 */
Angus Kongc195e7a2014-02-20 16:56:37 -08002420 public void startDecodingJob(final LocalData data,
2421 final com.android.camera.util.Callback<Bitmap> callback) {
Angus Kong50521172014-01-17 17:23:59 -08002422 PeekAnimationHandler.this.obtainMessage(0 /** dummy integer **/,
2423 new DataAndCallback(data, callback)).sendToTarget();
2424 }
2425
2426 @Override
2427 public void handleMessage(Message msg) {
2428 final LocalData data = ((DataAndCallback) msg.obj).mData;
2429 final com.android.camera.util.Callback<Bitmap> callback =
2430 ((DataAndCallback) msg.obj).mCallback;
2431 if (data == null || callback == null) {
2432 return;
2433 }
2434
2435 final Bitmap bitmap;
2436 switch (data.getLocalDataType()) {
Angus Kong50521172014-01-17 17:23:59 -08002437 case LocalData.LOCAL_IN_PROGRESS_DATA:
Angus Kong571a8c32014-03-13 12:53:03 -07002438 byte[] jpegData = Storage.getJpegForSession(data.getUri());
2439 if (jpegData != null) {
2440 bitmap = BitmapFactory.decodeByteArray(jpegData, 0, jpegData.length);
2441 } else {
2442 bitmap = null;
2443 }
2444 break;
2445
2446 case LocalData.LOCAL_IMAGE:
Angus Kong50521172014-01-17 17:23:59 -08002447 FileInputStream stream;
2448 try {
2449 stream = new FileInputStream(data.getPath());
2450 } catch (FileNotFoundException e) {
2451 Log.e(TAG, "File not found:" + data.getPath());
2452 return;
2453 }
Angus Kongc195e7a2014-02-20 16:56:37 -08002454 Point dim = CameraUtil.resizeToFill(data.getWidth(), data.getHeight(),
2455 data.getRotation(), mAboveFilmstripControlLayout.getWidth(),
2456 mAboveFilmstripControlLayout.getMeasuredHeight());
2457 if (data.getRotation() % 180 != 0) {
2458 int dummy = dim.x;
2459 dim.x = dim.y;
2460 dim.y = dummy;
2461 }
Angus Kong50521172014-01-17 17:23:59 -08002462 bitmap = LocalDataUtil
2463 .loadImageThumbnailFromStream(stream, data.getWidth(), data.getHeight(),
Angus Kongc195e7a2014-02-20 16:56:37 -08002464 (int) (dim.x * 0.7f), (int) (dim.y * 0.7),
2465 data.getRotation(), MAX_PEEK_BITMAP_PIXELS);
Angus Kong50521172014-01-17 17:23:59 -08002466 break;
2467
2468 case LocalData.LOCAL_VIDEO:
2469 bitmap = LocalDataUtil.loadVideoThumbnail(data.getPath());
2470 break;
2471
2472 default:
2473 bitmap = null;
2474 break;
2475 }
2476
2477 if (bitmap == null) {
2478 return;
2479 }
2480
2481 mMainHandler.post(new Runnable() {
2482 @Override
2483 public void run() {
2484 callback.onCallback(bitmap);
Angus Kong50521172014-01-17 17:23:59 -08002485 }
2486 });
2487 }
2488 }
Sascha Haeberlingd114a772014-02-28 21:27:27 -08002489
2490 private void showDetailsDialog(int dataId) {
2491 final LocalData data = mDataAdapter.getLocalData(dataId);
2492 if (data == null) {
2493 return;
2494 }
2495 MediaDetails details = data.getMediaDetails(getAndroidContext());
2496 if (details == null) {
2497 return;
2498 }
2499 Dialog detailDialog = DetailsDialog.create(CameraActivity.this, details);
2500 detailDialog.show();
Andy Huibers10c58162014-03-29 14:06:54 -07002501 UsageStatistics.instance().mediaInteraction(
2502 fileNameFromDataID(dataId), MediaInteraction.InteractionType.DETAILS,
2503 NavigationChange.InteractionCause.BUTTON);
Sascha Haeberlingd114a772014-02-28 21:27:27 -08002504 }
2505
2506 /**
2507 * Show or hide action bar items depending on current data type.
2508 */
2509 private void updateActionBarMenu(LocalData data) {
2510 if (mActionBarMenu == null) {
2511 return;
2512 }
2513
2514 MenuItem detailsMenuItem = mActionBarMenu.findItem(R.id.action_details);
2515 if (detailsMenuItem == null) {
2516 return;
2517 }
2518
2519 int type = data.getLocalDataType();
2520 boolean showDetails = (type == LocalData.LOCAL_IMAGE) || (type == LocalData.LOCAL_VIDEO);
2521 detailsMenuItem.setVisible(showDetails);
2522 }
Michael Kolb8872c232013-01-29 10:33:22 -08002523}