blob: 55f1d40474cbee31438313c943fc9c0656c1c3f9 [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
Sascha Haeberling2fe3a3e2014-07-30 10:31:29 -070017
Michael Kolb8872c232013-01-29 10:33:22 -080018package com.android.camera;
19
Doris Liu742cd5b2013-09-12 16:17:43 -070020import android.animation.Animator;
Mangesh Ghiwarea5682ab2013-09-19 09:24:23 -070021import android.annotation.TargetApi;
ztenghuifa9e2cc2013-08-09 17:37:15 -070022import android.app.ActionBar;
Doris Liu6432cd62013-06-13 17:20:31 -070023import android.app.Activity;
Angus Kong01054e92013-12-10 11:06:18 -080024import android.app.AlertDialog;
Angus Kong26795a92014-02-20 09:18:09 -080025import android.app.Dialog;
Mangesh Ghiware30968d02013-10-02 14:38:12 -070026import android.content.ActivityNotFoundException;
Doris Liub84b9732013-06-18 17:14:26 -070027import android.content.BroadcastReceiver;
Doris Liu6432cd62013-06-13 17:20:31 -070028import android.content.ContentResolver;
Michael Kolb08650182013-02-25 19:43:56 -080029import android.content.Context;
Michael Kolb8872c232013-01-29 10:33:22 -080030import android.content.Intent;
Doris Liub84b9732013-06-18 17:14:26 -070031import android.content.IntentFilter;
Doris Liu3cf565c2013-02-15 10:55:37 -080032import android.content.pm.ActivityInfo;
Michael Kolb8872c232013-01-29 10:33:22 -080033import android.content.res.Configuration;
Angus Kong9f1db522013-11-09 16:25:59 -080034import android.graphics.Bitmap;
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;
Seth Raphael02c129a2014-05-19 21:46:04 -070038import android.graphics.RectF;
Angus Kong9f1db522013-11-09 16:25:59 -080039import android.graphics.SurfaceTexture;
Spike Sprague4cc78bb2014-08-21 10:16:10 -070040import android.graphics.drawable.ColorDrawable;
Angus Kong6c0c7f12014-01-15 14:40:27 -080041import android.graphics.drawable.Drawable;
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;
Kevin Gabayan516c11a2014-06-13 20:49:48 +000046import android.os.AsyncTask;
47import android.os.Build;
48import android.os.Bundle;
49import android.os.Handler;
50import android.os.HandlerThread;
51import 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;
Andy Huibersc8924b22014-05-20 15:17:06 -070055import android.text.TextUtils;
Doris Liu7cbecee2014-01-30 12:29:27 -080056import android.util.CameraPerformanceTracker;
Sascha Haeberlinge8959e72014-01-31 15:21:02 +010057import android.view.ContextMenu;
58import android.view.ContextMenu.ContextMenuInfo;
Michael Kolb8872c232013-01-29 10:33:22 -080059import android.view.KeyEvent;
Sascha Haeberlingd114a772014-02-28 21:27:27 -080060import android.view.Menu;
Sascha Haeberlinge8959e72014-01-31 15:21:02 +010061import android.view.MenuInflater;
ztenghui0353ca22013-08-13 13:53:16 -070062import android.view.MenuItem;
Doris Liu742cd5b2013-09-12 16:17:43 -070063import android.view.MotionEvent;
Michael Kolb8872c232013-01-29 10:33:22 -080064import android.view.View;
Sascha Haeberling099b49b2014-04-08 07:08:46 -070065import android.view.View.OnSystemUiVisibilityChangeListener;
Doris Liu6432cd62013-06-13 17:20:31 -070066import android.view.ViewGroup;
Michael Kolb08650182013-02-25 19:43:56 -080067import android.view.Window;
68import android.view.WindowManager;
Angus Kong653c43b2013-08-21 18:28:43 -070069import android.widget.FrameLayout;
Doris Liu6432cd62013-06-13 17:20:31 -070070import android.widget.ImageView;
Mangesh Ghiwarecd2eeb02013-08-23 13:28:21 -070071import android.widget.ShareActionProvider;
Sascha Haeberlingaa52b3d2014-07-01 12:30:30 -070072
Angus Kong9f1db522013-11-09 16:25:59 -080073import com.android.camera.app.AppController;
Doris Liuf55f3c42013-11-20 00:24:46 -080074import com.android.camera.app.CameraAppUI;
Angus Kong20fad242013-11-11 18:23:46 -080075import com.android.camera.app.CameraController;
Angus Kong20fad242013-11-11 18:23:46 -080076import com.android.camera.app.CameraProvider;
Angus Kongc4e66562013-11-22 23:03:21 -080077import com.android.camera.app.CameraServices;
Kevin Gabayanffbc43c2013-12-09 11:41:50 -080078import com.android.camera.app.LocationManager;
Kevin Gabayan0aeb0c82014-04-08 11:12:05 -070079import com.android.camera.app.MemoryManager;
Kevin Gabayan05ee74d2014-04-08 16:25:23 -070080import com.android.camera.app.MemoryQuery;
Sascha Haeberling08b3c942014-07-30 17:48:52 -070081import com.android.camera.app.ModuleManager;
Angus Kong20fad242013-11-11 18:23:46 -080082import com.android.camera.app.ModuleManagerImpl;
Kevin Gabayanfb333362014-06-02 14:48:20 -070083import com.android.camera.app.MotionManager;
Angus Kong9f1db522013-11-09 16:25:59 -080084import com.android.camera.app.OrientationManager;
85import com.android.camera.app.OrientationManagerImpl;
Doris Liu6432cd62013-06-13 17:20:31 -070086import com.android.camera.data.CameraDataAdapter;
Angus Kong8e5e4ee2013-07-30 11:36:00 -070087import com.android.camera.data.FixedLastDataAdapter;
Doris Liu6432cd62013-06-13 17:20:31 -070088import com.android.camera.data.LocalData;
Angus Kong8e5e4ee2013-07-30 11:36:00 -070089import com.android.camera.data.LocalDataAdapter;
Angus Kong50521172014-01-17 17:23:59 -080090import com.android.camera.data.LocalDataUtil;
Sascha Haeberling910c1a92014-05-13 13:36:44 -070091import com.android.camera.data.LocalDataViewType;
Angus Kong571a8c32014-03-13 12:53:03 -070092import com.android.camera.data.LocalMediaData;
ztenghui064d6002013-09-05 15:47:58 -070093import com.android.camera.data.LocalMediaObserver;
Angus Kong571a8c32014-03-13 12:53:03 -070094import com.android.camera.data.LocalSessionData;
Angus Kong26795a92014-02-20 09:18:09 -080095import com.android.camera.data.MediaDetails;
Angus Kong810b0b62014-04-30 11:26:21 -070096import com.android.camera.data.MetadataLoader;
Angus Kong8a2350a2013-12-16 15:02:34 -080097import com.android.camera.data.PanoramaMetadataLoader;
98import com.android.camera.data.RgbzMetadataLoader;
Angus Kongbd260692013-08-07 14:52:56 -070099import com.android.camera.data.SimpleViewData;
Angus Kong2bca2102014-03-11 16:27:30 -0700100import com.android.camera.debug.Log;
Angus Kong01054e92013-12-10 11:06:18 -0800101import com.android.camera.filmstrip.FilmstripContentPanel;
Angus Kong62848152013-11-08 17:25:29 -0800102import com.android.camera.filmstrip.FilmstripController;
Erin Dahlgrene346fb22014-02-19 17:23:01 -0800103import com.android.camera.hardware.HardwareSpec;
104import com.android.camera.hardware.HardwareSpecImpl;
Erin Dahlgren0a6a8d82014-01-09 22:17:38 -0800105import com.android.camera.module.ModuleController;
Angus Kong612321f2013-11-18 16:17:43 -0800106import com.android.camera.module.ModulesInfo;
Sascha Haeberling08b3c942014-07-30 17:48:52 -0700107import com.android.camera.one.OneCameraManager;
Seth Raphael16bca012014-03-21 09:56:11 -0700108import com.android.camera.session.CaptureSession;
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800109import com.android.camera.session.CaptureSessionManager;
110import com.android.camera.session.CaptureSessionManager.SessionListener;
Alan Newberger2307b602014-08-05 09:56:17 -0700111import com.android.camera.settings.AppUpgrader;
Sascha Haeberlingde303232014-02-07 02:30:53 +0100112import com.android.camera.settings.CameraSettingsActivity;
Erin Dahlgren6190c362014-06-13 14:12:08 -0700113import com.android.camera.settings.Keys;
Erin Dahlgren357b7672013-11-20 17:38:14 -0800114import com.android.camera.settings.SettingsManager;
Sascha Haeberlingde303232014-02-07 02:30:53 +0100115import com.android.camera.settings.SettingsUtil;
Sascha Haeberlinga5a08d72013-09-11 20:30:52 -0700116import com.android.camera.tinyplanet.TinyPlanetFragment;
Sascha Haeberlingc813ce12014-03-10 15:35:07 -0700117import com.android.camera.ui.AbstractTutorialOverlay;
Angus Kong26795a92014-02-20 09:18:09 -0800118import com.android.camera.ui.DetailsDialog;
Doris Liuf55f3c42013-11-20 00:24:46 -0800119import com.android.camera.ui.MainActivityLayout;
Doris Liu1c94b7d2013-11-09 19:13:44 -0800120import com.android.camera.ui.ModeListView;
Sascha Haeberling8c1a9222014-02-25 09:38:06 -0800121import com.android.camera.ui.ModeListView.ModeListVisibilityChangedListener;
Doris Liu06db7422013-12-09 19:36:25 -0800122import com.android.camera.ui.PreviewStatusListener;
Sascha Haeberling88ef7662013-08-15 17:19:22 -0700123import com.android.camera.util.ApiHelper;
Sascha Haeberlingde303232014-02-07 02:30:53 +0100124import com.android.camera.util.Callback;
Angus Kongb50b5cb2013-08-09 14:55:20 -0700125import com.android.camera.util.CameraUtil;
Alan Newberger80461c22014-02-03 15:03:26 -0800126import com.android.camera.util.GalleryHelper;
Ruben Brunka9d66bd2013-09-06 11:56:32 -0700127import com.android.camera.util.GcamHelper;
Erin Dahlgren26a4bb92014-06-27 11:18:36 -0700128import com.android.camera.util.GoogleHelpHelper;
Alan Newberger761306f2013-10-30 12:51:21 -0700129import com.android.camera.util.IntentHelper;
Sascha Haeberling88ef7662013-08-15 17:19:22 -0700130import com.android.camera.util.PhotoSphereHelper.PanoramaViewHelper;
Sascha Haeberlingc26a3282014-02-19 08:39:28 -0800131import com.android.camera.util.ReleaseDialogHelper;
Seth Raphaelcbd82672013-11-05 10:12:36 -0800132import com.android.camera.util.UsageStatistics;
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800133import com.android.camera.widget.FilmstripView;
Sam Juddde3e9ab2014-03-17 13:07:22 -0700134import com.android.camera.widget.Preloader;
Sascha Haeberling8e963a52013-08-06 11:43:02 -0700135import com.android.camera2.R;
Sol Boucher5a344962014-06-17 14:05:08 -0700136import com.android.ex.camera2.portability.CameraAgent;
137import com.android.ex.camera2.portability.CameraAgentFactory;
138import com.android.ex.camera2.portability.CameraSettings;
Sam Judd4021c892014-03-17 12:57:50 -0700139import com.bumptech.glide.Glide;
Sam Judd632eaaf2014-06-24 13:31:02 -0700140import com.bumptech.glide.GlideBuilder;
141import com.bumptech.glide.MemoryCategory;
142import com.bumptech.glide.load.engine.executor.FifoPriorityThreadPoolExecutor;
Seth Raphael5e09d012013-12-18 13:45:03 -0800143import com.google.common.logging.eventprotos;
Andy Huibers10c58162014-03-29 14:06:54 -0700144import com.google.common.logging.eventprotos.ForegroundEvent.ForegroundSource;
Sascha Haeberling099b49b2014-04-08 07:08:46 -0700145import com.google.common.logging.eventprotos.MediaInteraction;
146import com.google.common.logging.eventprotos.NavigationChange;
Michael Kolb8872c232013-01-29 10:33:22 -0800147
Seth Raphaelcbd82672013-11-05 10:12:36 -0800148import java.io.File;
Angus Kong50521172014-01-17 17:23:59 -0800149import java.io.FileInputStream;
150import java.io.FileNotFoundException;
Sascha Haeberling846d3ab2014-02-04 12:48:55 +0100151import java.lang.ref.WeakReference;
Erin Dahlgrenf63967a2014-01-02 13:57:43 -0800152import java.util.ArrayList;
Kevin Gabayan0aeb0c82014-04-08 11:12:05 -0700153import java.util.HashMap;
Sascha Haeberling8793eff2014-01-15 16:33:59 -0800154import java.util.List;
Andy Huibersc8924b22014-05-20 15:17:06 -0700155import java.util.concurrent.TimeUnit;
Seth Raphaelcbd82672013-11-05 10:12:36 -0800156
Doris Liu6432cd62013-06-13 17:20:31 -0700157public class CameraActivity extends Activity
Sol Boucher5a344962014-06-17 14:05:08 -0700158 implements AppController, CameraAgent.CameraOpenCallback,
Spike Spragueba97d192014-08-19 15:33:45 -0700159 ShareActionProvider.OnShareTargetSelectedListener,
Angus Kong9f1db522013-11-09 16:25:59 -0800160 OrientationManager.OnOrientationChangeListener {
Doris Liu6432cd62013-06-13 17:20:31 -0700161
Angus Kong2bca2102014-03-11 16:27:30 -0700162 private static final Log.Tag TAG = new Log.Tag("CameraActivity");
Doris Liu6432cd62013-06-13 17:20:31 -0700163
Doris Liu6432cd62013-06-13 17:20:31 -0700164 private static final String INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE =
165 "android.media.action.STILL_IMAGE_CAMERA_SECURE";
166 public static final String ACTION_IMAGE_CAPTURE_SECURE =
167 "android.media.action.IMAGE_CAPTURE_SECURE";
168
169 // The intent extra for camera from secure lock screen. True if the gallery
170 // should only show newly captured pictures. sSecureAlbumId does not
171 // increment. This is used when switching between camera, camcorder, and
172 // panorama. If the extra is not set, it is in the normal camera mode.
173 public static final String SECURE_CAMERA_EXTRA = "secure_camera";
174
Erin Dahlgren6190c362014-06-13 14:12:08 -0700175 public static final String MODULE_SCOPE_PREFIX = "_preferences_module_";
176 public static final String CAMERA_SCOPE_PREFIX = "_preferences_camera_";
177
Angus Kong13e87c42013-11-25 10:02:47 -0800178 private static final int MSG_CLEAR_SCREEN_ON_FLAG = 2;
Sascha Haeberling846d3ab2014-02-04 12:48:55 +0100179 private static final long SCREEN_DELAY_MS = 2 * 60 * 1000; // 2 mins.
Angus Kong50521172014-01-17 17:23:59 -0800180 private static final int MAX_PEEK_BITMAP_PIXELS = 1600000; // 1.6 * 4 MBs.
Sam Juddde3e9ab2014-03-17 13:07:22 -0700181 /** Load metadata for 10 items ahead of our current. */
182 private static final int FILMSTRIP_PRELOAD_AHEAD_ITEMS = 10;
Sascha Haeberling846d3ab2014-02-04 12:48:55 +0100183
184 /** Should be used wherever a context is needed. */
185 private Context mAppContext;
Doris Liuaa874422013-09-18 19:43:12 -0700186
Angus Kong20fad242013-11-11 18:23:46 -0800187 /**
188 * Whether onResume should reset the view to the preview.
189 */
Sascha Haeberlingb7639c62013-09-09 14:42:43 -0700190 private boolean mResetToPreviewOnResume = true;
191
Angus Kong20fad242013-11-11 18:23:46 -0800192 /**
193 * This data adapter is used by FilmStripView.
194 */
Angus Kong8e5e4ee2013-07-30 11:36:00 -0700195 private LocalDataAdapter mDataAdapter;
Angus Kong8e5e4ee2013-07-30 11:36:00 -0700196
Erin Dahlgrenc120b0f2013-11-19 10:53:49 -0800197 private SettingsManager mSettingsManager;
Doris Liu70576b62013-11-14 20:30:33 -0800198 private ModeListView mModeListView;
Sascha Haeberling2d11fcf2014-03-13 09:04:32 -0700199 private boolean mModeListVisible = false;
Erin Dahlgrenc120b0f2013-11-19 10:53:49 -0800200 private int mCurrentModeIndex;
Doris Liu6432cd62013-06-13 17:20:31 -0700201 private CameraModule mCurrentModule;
Angus Kong20fad242013-11-11 18:23:46 -0800202 private ModuleManagerImpl mModuleManager;
Angus Kong653c43b2013-08-21 18:28:43 -0700203 private FrameLayout mAboveFilmstripControlLayout;
Angus Kong62848152013-11-08 17:25:29 -0800204 private FilmstripController mFilmstripController;
Angus Kongfaaee012013-12-07 00:38:46 -0800205 private boolean mFilmstripVisible;
Sascha Haeberling2d11fcf2014-03-13 09:04:32 -0700206 /** Whether the filmstrip fully covers the preview. */
207 private boolean mFilmstripCoversPreview = false;
Doris Liu6432cd62013-06-13 17:20:31 -0700208 private int mResultCodeForTesting;
209 private Intent mResultDataForTesting;
210 private OnScreenHint mStorageHint;
Sascha Haeberlinge3e270f2014-04-02 23:27:50 -0700211 private final Object mStorageSpaceLock = new Object();
Angus Kong2dcc0a92013-09-25 13:00:08 -0700212 private long mStorageSpaceBytes = Storage.LOW_STORAGE_THRESHOLD_BYTES;
Doris Liu3cf565c2013-02-15 10:55:37 -0800213 private boolean mAutoRotateScreen;
Doris Liu6432cd62013-06-13 17:20:31 -0700214 private boolean mSecureCamera;
Doris Liu6432cd62013-06-13 17:20:31 -0700215 private int mLastRawOrientation;
Angus Kong9f1db522013-11-09 16:25:59 -0800216 private OrientationManagerImpl mOrientationManager;
Erin Dahlgren21c21a62013-11-19 16:37:38 -0800217 private LocationManager mLocationManager;
Erin Dahlgren8a2933b2013-12-06 12:07:33 -0800218 private ButtonManager mButtonManager;
Doris Liu6432cd62013-06-13 17:20:31 -0700219 private Handler mMainHandler;
Sascha Haeberlingf1f51862013-07-31 11:28:21 -0700220 private PanoramaViewHelper mPanoramaViewHelper;
ztenghuifa9e2cc2013-08-09 17:37:15 -0700221 private ActionBar mActionBar;
Angus Kong653c43b2013-08-21 18:28:43 -0700222 private ViewGroup mUndoDeletionBar;
Doris Liu742cd5b2013-09-12 16:17:43 -0700223 private boolean mIsUndoingDeletion = false;
Sascha Haeberlingca82f502014-07-15 08:54:40 -0700224 private boolean mIsActivityRunning = false;
Doris Liu3cf565c2013-02-15 10:55:37 -0800225
Sascha Haeberling280fd3e2013-11-21 13:52:15 -0800226 private final Uri[] mNfcPushUris = new Uri[1];
Mangesh Ghiwarea5682ab2013-09-19 09:24:23 -0700227
ztenghui064d6002013-09-05 15:47:58 -0700228 private LocalMediaObserver mLocalImagesObserver;
229 private LocalMediaObserver mLocalVideosObserver;
Mangesh Ghiwarecd2eeb02013-08-23 13:28:21 -0700230
Doris Liu742cd5b2013-09-12 16:17:43 -0700231 private boolean mPendingDeletion = false;
Sascha Haeberling5199c202013-09-05 17:10:19 -0700232
Angus Kong20fad242013-11-11 18:23:46 -0800233 private CameraController mCameraController;
Erin Dahlgrenc120b0f2013-11-19 10:53:49 -0800234 private boolean mPaused;
Doris Liuf55f3c42013-11-20 00:24:46 -0800235 private CameraAppUI mCameraAppUI;
Angus Kong20fad242013-11-11 18:23:46 -0800236
Angus Kong50521172014-01-17 17:23:59 -0800237 private PeekAnimationHandler mPeekAnimationHandler;
238 private HandlerThread mPeekAnimationThread;
239
Angus Kong6c0c7f12014-01-15 14:40:27 -0800240 private Intent mGalleryIntent;
Kevin Gabayana0e83472014-01-15 15:21:13 -0800241 private long mOnCreateTime;
Christian Wyglendowski6fe8c822013-11-26 14:16:04 -0800242
Sascha Haeberlingd114a772014-02-28 21:27:27 -0800243 private Menu mActionBarMenu;
Sam Juddde3e9ab2014-03-17 13:07:22 -0700244 private Preloader<Integer, AsyncTask> mPreloader;
Sascha Haeberlingd114a772014-02-28 21:27:27 -0800245
Sascha Haeberling2d4be252014-08-27 17:56:08 -0700246 /** Can be used to play custom sounds. */
247 private SoundPlayer mSoundPlayer;
248
Sascha Haeberling099b49b2014-04-08 07:08:46 -0700249 private static final int LIGHTS_OUT_DELAY_MS = 4000;
Spike Spraguec7ab9c42014-08-06 12:13:00 -0700250 private final int BASE_SYS_UI_VISIBILITY =
Alan Newbergerd67c02e2014-08-13 16:28:26 -0700251 View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
Spike Spraguec7ab9c42014-08-06 12:13:00 -0700252 | View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
Sascha Haeberling099b49b2014-04-08 07:08:46 -0700253 private final Runnable mLightsOutRunnable = new Runnable() {
254 @Override
255 public void run() {
256 getWindow().getDecorView().setSystemUiVisibility(
257 BASE_SYS_UI_VISIBILITY | View.SYSTEM_UI_FLAG_LOW_PROFILE);
258 }
259 };
Kevin Gabayan0aeb0c82014-04-08 11:12:05 -0700260 private MemoryManager mMemoryManager;
Kevin Gabayanfb333362014-06-02 14:48:20 -0700261 private MotionManager mMotionManager;
Sascha Haeberling099b49b2014-04-08 07:08:46 -0700262
Spike Sprague0f3c4b42013-12-10 19:50:17 -0800263 @Override
264 public CameraAppUI getCameraAppUI() {
265 return mCameraAppUI;
266 }
267
Erin Dahlgren6190c362014-06-13 14:12:08 -0700268 @Override
269 public ModuleManager getModuleManager() {
270 return mModuleManager;
271 }
272
Doris Liub84b9732013-06-18 17:14:26 -0700273 // close activity when screen turns off
Sascha Haeberling280fd3e2013-11-21 13:52:15 -0800274 private final BroadcastReceiver mScreenOffReceiver = new BroadcastReceiver() {
Doris Liub84b9732013-06-18 17:14:26 -0700275 @Override
276 public void onReceive(Context context, Intent intent) {
277 finish();
278 }
279 };
280
Sascha Haeberling2d4be252014-08-27 17:56:08 -0700281 private final ActionBar.OnMenuVisibilityListener mOnMenuVisibilityListener =
Spike Spragueba97d192014-08-19 15:33:45 -0700282 new ActionBar.OnMenuVisibilityListener() {
283 @Override
284 public void onMenuVisibilityChanged(boolean isVisible) {
285 // TODO: Remove this or bring back the original implementation: cancel
286 // auto-hide actionbar.
287 }
288 };
289
Angus Kong13e87c42013-11-25 10:02:47 -0800290 /**
291 * Whether the screen is kept turned on.
292 */
293 private boolean mKeepScreenOn;
Angus Kong53ae0412013-12-01 23:21:49 -0800294 private int mLastLayoutOrientation;
Angus Kong7ae25c22014-02-25 10:37:39 -0800295 private final CameraAppUI.BottomPanel.Listener mMyFilmstripBottomControlListener =
296 new CameraAppUI.BottomPanel.Listener() {
Angus Kongb2510252013-12-10 22:58:15 -0800297
298 /**
Sascha Haeberling846d3ab2014-02-04 12:48:55 +0100299 * If the current photo is a photo sphere, this will launch the
300 * Photo Sphere panorama viewer.
Angus Kongb2510252013-12-10 22:58:15 -0800301 */
302 @Override
Angus Kong8a2350a2013-12-16 15:02:34 -0800303 public void onExternalViewer() {
304 if (mPanoramaViewHelper == null) {
305 return;
306 }
307 final LocalData data = getCurrentLocalData();
308 if (data == null) {
Sascha Haeberlingc2e68132014-08-13 11:43:57 -0700309 Log.w(TAG, "Cannot open null data.");
Angus Kong8a2350a2013-12-16 15:02:34 -0800310 return;
311 }
Angus Kong571a8c32014-03-13 12:53:03 -0700312 final Uri contentUri = data.getUri();
Angus Kong8a2350a2013-12-16 15:02:34 -0800313 if (contentUri == Uri.EMPTY) {
Sascha Haeberlingc2e68132014-08-13 11:43:57 -0700314 Log.w(TAG, "Cannot open empty URL.");
Angus Kong8a2350a2013-12-16 15:02:34 -0800315 return;
316 }
317
Sascha Haeberling7190c6a2014-02-21 10:11:31 -0800318 if (PanoramaMetadataLoader.isPanoramaAndUseViewer(data)) {
Erin Dahlgren013ad4e2014-02-26 10:48:08 -0800319 mPanoramaViewHelper.showPanorama(CameraActivity.this, contentUri);
Angus Kong8a2350a2013-12-16 15:02:34 -0800320 } else if (RgbzMetadataLoader.hasRGBZData(data)) {
321 mPanoramaViewHelper.showRgbz(contentUri);
Erin Dahlgren6190c362014-06-13 14:12:08 -0700322 if (mSettingsManager.getBoolean(SettingsManager.SCOPE_GLOBAL,
323 Keys.KEY_SHOULD_SHOW_REFOCUS_VIEWER_CLING)) {
324 mSettingsManager.set(SettingsManager.SCOPE_GLOBAL,
325 Keys.KEY_SHOULD_SHOW_REFOCUS_VIEWER_CLING, false);
Doris Liue7d7b9e2014-03-31 15:27:40 -0700326 mCameraAppUI.clearClingForViewer(
327 CameraAppUI.BottomPanel.VIEWER_REFOCUS);
328 }
Angus Kongb2510252013-12-10 22:58:15 -0800329 }
330 }
331
332 @Override
333 public void onEdit() {
334 LocalData data = getCurrentLocalData();
335 if (data == null) {
Sascha Haeberlingc2e68132014-08-13 11:43:57 -0700336 Log.w(TAG, "Cannot edit null data.");
Angus Kongb2510252013-12-10 22:58:15 -0800337 return;
338 }
Andy Huibers10c58162014-03-29 14:06:54 -0700339 final int currentDataId = getCurrentDataId();
340 UsageStatistics.instance().mediaInteraction(fileNameFromDataID(currentDataId),
341 MediaInteraction.InteractionType.EDIT,
Andy Huibersebd95372014-05-12 14:44:13 -0700342 NavigationChange.InteractionCause.BUTTON,
343 fileAgeFromDataID(currentDataId));
Angus Kongb2510252013-12-10 22:58:15 -0800344 launchEditor(data);
345 }
346
347 @Override
348 public void onTinyPlanet() {
349 LocalData data = getCurrentLocalData();
350 if (data == null) {
Sascha Haeberlingc2e68132014-08-13 11:43:57 -0700351 Log.w(TAG, "Cannot edit tiny planet on null data.");
Angus Kongb2510252013-12-10 22:58:15 -0800352 return;
353 }
354 launchTinyPlanetEditor(data);
355 }
356
Angus Konge0aff892013-12-11 20:51:01 -0800357 @Override
358 public void onDelete() {
359 final int currentDataId = getCurrentDataId();
Andy Huibers10c58162014-03-29 14:06:54 -0700360 UsageStatistics.instance().mediaInteraction(fileNameFromDataID(currentDataId),
361 MediaInteraction.InteractionType.DELETE,
Andy Huibersebd95372014-05-12 14:44:13 -0700362 NavigationChange.InteractionCause.BUTTON,
363 fileAgeFromDataID(currentDataId));
Angus Konge0aff892013-12-11 20:51:01 -0800364 removeData(currentDataId);
365 }
366
367 @Override
368 public void onShare() {
Angus Kong662fbf42013-12-12 13:22:03 -0800369 final LocalData data = getCurrentLocalData();
Sascha Haeberlingc2e68132014-08-13 11:43:57 -0700370 if (data == null) {
371 Log.w(TAG, "Cannot share null data.");
372 return;
373 }
374
Andy Huibers10c58162014-03-29 14:06:54 -0700375 final int currentDataId = getCurrentDataId();
376 UsageStatistics.instance().mediaInteraction(fileNameFromDataID(currentDataId),
377 MediaInteraction.InteractionType.SHARE,
Andy Huibersebd95372014-05-12 14:44:13 -0700378 NavigationChange.InteractionCause.BUTTON,
379 fileAgeFromDataID(currentDataId));
Sascha Haeberling7190c6a2014-02-21 10:11:31 -0800380 // If applicable, show release information before this item
381 // is shared.
Alan Newberger443a1a62014-05-06 16:47:34 -0700382 if (ReleaseDialogHelper.shouldShowReleaseInfoDialogOnShare(data)) {
Sascha Haeberling7190c6a2014-02-21 10:11:31 -0800383 ReleaseDialogHelper.showReleaseInfoDialog(CameraActivity.this,
384 new Callback<Void>() {
385 @Override
386 public void onCallback(Void result) {
387 share(data);
388 }
389 });
390 } else {
391 share(data);
392 }
393 }
394
395 private void share(LocalData data) {
Angus Kong662fbf42013-12-12 13:22:03 -0800396 Intent shareIntent = getShareIntentByData(data);
397 if (shareIntent != null) {
Angus Konge4002f32013-12-13 22:24:11 -0800398 try {
Angus Kong0eaf0162013-12-16 15:53:30 -0800399 launchActivityByIntent(shareIntent);
Angus Konge4002f32013-12-13 22:24:11 -0800400 mCameraAppUI.getFilmstripBottomControls().setShareEnabled(false);
401 } catch (ActivityNotFoundException ex) {
402 // Nothing.
403 }
Angus Kong662fbf42013-12-12 13:22:03 -0800404 }
Angus Konge0aff892013-12-11 20:51:01 -0800405 }
406
Angus Konge0aff892013-12-11 20:51:01 -0800407 private int getCurrentDataId() {
408 return mFilmstripController.getCurrentId();
409 }
410
Angus Kongb2510252013-12-10 22:58:15 -0800411 private LocalData getCurrentLocalData() {
Angus Konge0aff892013-12-11 20:51:01 -0800412 return mDataAdapter.getLocalData(getCurrentDataId());
Angus Kongb2510252013-12-10 22:58:15 -0800413 }
Angus Kong662fbf42013-12-12 13:22:03 -0800414
415 /**
Sascha Haeberling846d3ab2014-02-04 12:48:55 +0100416 * Sets up the share intent and NFC properly according to the
417 * data.
Angus Kong662fbf42013-12-12 13:22:03 -0800418 *
419 * @param data The data to be shared.
420 */
421 private Intent getShareIntentByData(final LocalData data) {
422 Intent intent = null;
Angus Kong571a8c32014-03-13 12:53:03 -0700423 final Uri contentUri = data.getUri();
Sascha Haeberling910c1a92014-05-13 13:36:44 -0700424 final String msgShareTo = getResources().getString(R.string.share_to);
425
Angus Kong8a2350a2013-12-16 15:02:34 -0800426 if (PanoramaMetadataLoader.isPanorama360(data) &&
Angus Kong571a8c32014-03-13 12:53:03 -0700427 data.getUri() != Uri.EMPTY) {
Angus Kong662fbf42013-12-12 13:22:03 -0800428 intent = new Intent(Intent.ACTION_SEND);
429 intent.setType("application/vnd.google.panorama360+jpg");
430 intent.putExtra(Intent.EXTRA_STREAM, contentUri);
431 } else if (data.isDataActionSupported(LocalData.DATA_ACTION_SHARE)) {
432 final String mimeType = data.getMimeType();
433 intent = getShareIntentFromType(mimeType);
434 if (intent != null) {
435 intent.putExtra(Intent.EXTRA_STREAM, contentUri);
436 intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
437 }
Sascha Haeberling910c1a92014-05-13 13:36:44 -0700438 intent = Intent.createChooser(intent, msgShareTo);
Angus Kong662fbf42013-12-12 13:22:03 -0800439 }
440 return intent;
441 }
442
443 /**
444 * Get the share intent according to the mimeType
445 *
446 * @param mimeType The mimeType of current data.
Sascha Haeberling846d3ab2014-02-04 12:48:55 +0100447 * @return the video/image's ShareIntent or null if mimeType is
448 * invalid.
Angus Kong662fbf42013-12-12 13:22:03 -0800449 */
450 private Intent getShareIntentFromType(String mimeType) {
451 // Lazily create the intent object.
452 Intent intent = new Intent(Intent.ACTION_SEND);
453 if (mimeType.startsWith("video/")) {
454 intent.setType("video/*");
455 } else {
456 if (mimeType.startsWith("image/")) {
457 intent.setType("image/*");
458 } else {
459 Log.w(TAG, "unsupported mimeType " + mimeType);
460 }
461 }
462 return intent;
463 }
Sascha Haeberling597c1a02014-03-06 11:46:06 -0800464
465 @Override
466 public void onProgressErrorClicked() {
467 LocalData data = getCurrentLocalData();
468 getServices().getCaptureSessionManager().removeErrorMessage(
Angus Kong571a8c32014-03-13 12:53:03 -0700469 data.getUri());
Sascha Haeberling597c1a02014-03-06 11:46:06 -0800470 updateBottomControlsByData(data);
471 }
Angus Kongb2510252013-12-10 22:58:15 -0800472 };
Angus Kong13e87c42013-11-25 10:02:47 -0800473
Angus Kong20fad242013-11-11 18:23:46 -0800474 @Override
Sol Boucher5a344962014-06-17 14:05:08 -0700475 public void onCameraOpened(CameraAgent.CameraProxy camera) {
Angus Kong0b9eb5b2014-04-30 15:03:33 -0700476 if (mPaused) {
477 return;
478 }
Erin Dahlgrene346fb22014-02-19 17:23:01 -0800479 /**
480 * The current UI requires that the flash option visibility in front-facing
481 * camera be
482 * * disabled if back facing camera supports flash
483 * * hidden if back facing camera does not support flash
484 * We save whether back facing camera supports flash because we cannot get
485 * this in front facing camera without a camera switch.
486 *
487 * If this preference is cleared, we also need to clear the camera facing
488 * setting so we default to opening the camera in back facing camera, and
489 * can save this flash support value again.
490 */
Erin Dahlgren6190c362014-06-13 14:12:08 -0700491 if (!mSettingsManager.isSet(SettingsManager.SCOPE_GLOBAL,
492 Keys.KEY_FLASH_SUPPORTED_BACK_CAMERA)) {
Angus Kong831347d2014-06-16 16:07:28 -0700493 HardwareSpec hardware =
494 new HardwareSpecImpl(getCameraProvider(), camera.getCapabilities());
Erin Dahlgren6190c362014-06-13 14:12:08 -0700495 mSettingsManager.set(SettingsManager.SCOPE_GLOBAL,
496 Keys.KEY_FLASH_SUPPORTED_BACK_CAMERA,
497 hardware.isFlashSupported());
Erin Dahlgrene346fb22014-02-19 17:23:01 -0800498 }
499
Erin Dahlgrenc120b0f2013-11-19 10:53:49 -0800500 if (!mModuleManager.getModuleAgent(mCurrentModeIndex).requestAppForCamera()) {
Angus Kong20fad242013-11-11 18:23:46 -0800501 // We shouldn't be here. Just close the camera and leave.
Angus Kong0b9eb5b2014-04-30 15:03:33 -0700502 mCameraController.closeCamera(false);
Angus Kong20fad242013-11-11 18:23:46 -0800503 throw new IllegalStateException("Camera opened but the module shouldn't be " +
504 "requesting");
505 }
Angus Kong13e87c42013-11-25 10:02:47 -0800506 if (mCurrentModule != null) {
Spike Spragueabf54e22014-03-27 15:41:28 -0700507 resetExposureCompensationToDefault(camera);
Angus Kong13e87c42013-11-25 10:02:47 -0800508 mCurrentModule.onCameraAvailable(camera);
Angus Kong20fad242013-11-11 18:23:46 -0800509 }
Erin Dahlgren1648c362014-01-06 15:06:04 -0800510 mCameraAppUI.onChangeCamera();
Angus Kong20fad242013-11-11 18:23:46 -0800511 }
512
Sol Boucher5a344962014-06-17 14:05:08 -0700513 private void resetExposureCompensationToDefault(CameraAgent.CameraProxy camera) {
Spike Spragueabf54e22014-03-27 15:41:28 -0700514 // Reset the exposure compensation before handing the camera to module.
Angus Kong6607dae2014-06-10 16:07:45 -0700515 CameraSettings cameraSettings = camera.getSettings();
516 cameraSettings.setExposureCompensationIndex(0);
517 camera.applySettings(cameraSettings);
Spike Spragueabf54e22014-03-27 15:41:28 -0700518 }
519
Angus Kong20fad242013-11-11 18:23:46 -0800520 @Override
521 public void onCameraDisabled(int cameraId) {
Angus Kong0b9eb5b2014-04-30 15:03:33 -0700522 UsageStatistics.instance().cameraFailure(eventprotos.CameraFailure.FailureReason.SECURITY,
523 null);
524 Log.w(TAG, "Camera disabled: " + cameraId);
525 CameraUtil.showErrorAndFinish(this, R.string.camera_disabled);
Angus Kong20fad242013-11-11 18:23:46 -0800526 }
527
528 @Override
Angus Kong1b9d4fb2014-04-25 11:41:23 -0700529 public void onDeviceOpenFailure(int cameraId, String info) {
Sascha Haeberlinga83ec8a2014-03-31 13:22:17 -0700530 UsageStatistics.instance().cameraFailure(
Andy Huiberseaaf2932014-04-28 13:18:31 -0700531 eventprotos.CameraFailure.FailureReason.OPEN_FAILURE, info);
Angus Kong0b9eb5b2014-04-30 15:03:33 -0700532 Log.w(TAG, "Camera open failure: " + info);
Angus Kong20fad242013-11-11 18:23:46 -0800533 CameraUtil.showErrorAndFinish(this, R.string.cannot_connect_camera);
534 }
535
536 @Override
Angus Kong0b9eb5b2014-04-30 15:03:33 -0700537 public void onDeviceOpenedAlready(int cameraId, String info) {
538 Log.w(TAG, "Camera open already: " + cameraId + "," + info);
Angus Kong62753ae2014-02-10 10:53:54 -0800539 CameraUtil.showErrorAndFinish(this, R.string.cannot_connect_camera);
540 }
541
542 @Override
Sol Boucher5a344962014-06-17 14:05:08 -0700543 public void onReconnectionFailure(CameraAgent mgr, String info) {
Sascha Haeberlinga83ec8a2014-03-31 13:22:17 -0700544 UsageStatistics.instance().cameraFailure(
Andy Huiberseaaf2932014-04-28 13:18:31 -0700545 eventprotos.CameraFailure.FailureReason.RECONNECT_FAILURE, null);
Angus Kong0b9eb5b2014-04-30 15:03:33 -0700546 Log.w(TAG, "Camera reconnection failure:" + info);
Angus Kong20fad242013-11-11 18:23:46 -0800547 CameraUtil.showErrorAndFinish(this, R.string.cannot_connect_camera);
548 }
549
Sascha Haeberling846d3ab2014-02-04 12:48:55 +0100550 private static class MainHandler extends Handler {
551 final WeakReference<CameraActivity> mActivity;
Sascha Haeberlingde303232014-02-07 02:30:53 +0100552
Sascha Haeberling846d3ab2014-02-04 12:48:55 +0100553 public MainHandler(CameraActivity activity, Looper looper) {
Doris Liuaa874422013-09-18 19:43:12 -0700554 super(looper);
Sascha Haeberling846d3ab2014-02-04 12:48:55 +0100555 mActivity = new WeakReference<CameraActivity>(activity);
Doris Liuaa874422013-09-18 19:43:12 -0700556 }
557
558 @Override
559 public void handleMessage(Message msg) {
Sascha Haeberling846d3ab2014-02-04 12:48:55 +0100560 CameraActivity activity = mActivity.get();
561 if (activity == null) {
562 return;
563 }
Angus Kong13e87c42013-11-25 10:02:47 -0800564 switch (msg.what) {
Angus Kong13e87c42013-11-25 10:02:47 -0800565
Sascha Haeberling846d3ab2014-02-04 12:48:55 +0100566 case MSG_CLEAR_SCREEN_ON_FLAG: {
Sascha Haeberlingaa46ec92014-02-05 21:48:55 +0100567 if (!activity.mPaused) {
568 activity.getWindow().clearFlags(
569 WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
Angus Kong13e87c42013-11-25 10:02:47 -0800570 }
571 break;
572 }
Doris Liuaa874422013-09-18 19:43:12 -0700573 }
574 }
575 }
576
Seth Raphaelcbd82672013-11-05 10:12:36 -0800577 private String fileNameFromDataID(int dataID) {
578 final LocalData localData = mDataAdapter.getLocalData(dataID);
Sascha Haeberling27450ec2014-07-14 16:18:38 -0700579 if (localData == null) {
580 return "";
581 }
Seth Raphaelcbd82672013-11-05 10:12:36 -0800582
583 File localFile = new File(localData.getPath());
584 return localFile.getName();
585 }
586
Andy Huibersebd95372014-05-12 14:44:13 -0700587 private float fileAgeFromDataID(int dataID) {
588 final LocalData localData = mDataAdapter.getLocalData(dataID);
Sascha Haeberling2fe3a3e2014-07-30 10:31:29 -0700589 if (localData == null) {
590 return 0;
591 }
Andy Huibersebd95372014-05-12 14:44:13 -0700592
593 File localFile = new File(localData.getPath());
594 return 0.001f * (System.currentTimeMillis() - localFile.lastModified());
595 }
596
Angus Kong01054e92013-12-10 11:06:18 -0800597 private final FilmstripContentPanel.Listener mFilmstripListener =
598 new FilmstripContentPanel.Listener() {
Angus Kongfaaee012013-12-07 00:38:46 -0800599
600 @Override
Erin Dahlgren34881882014-01-29 18:13:34 -0800601 public void onSwipeOut() {
Erin Dahlgren34881882014-01-29 18:13:34 -0800602 }
603
604 @Override
Angus Kong73e09f32014-02-25 23:45:52 -0800605 public void onSwipeOutBegin() {
606 mActionBar.hide();
Spike Spragueba97d192014-08-19 15:33:45 -0700607 mCameraAppUI.hideBottomControls();
Sascha Haeberling2d11fcf2014-03-13 09:04:32 -0700608 mFilmstripCoversPreview = false;
609 updatePreviewVisibility();
Angus Kong73e09f32014-02-25 23:45:52 -0800610 }
611
612 @Override
Angus Kongfaaee012013-12-07 00:38:46 -0800613 public void onFilmstripHidden() {
614 mFilmstripVisible = false;
Andy Huibers10c58162014-03-29 14:06:54 -0700615 UsageStatistics.instance().changeScreen(currentUserInterfaceMode(),
616 NavigationChange.InteractionCause.SWIPE_RIGHT);
Angus Kongb2510252013-12-10 22:58:15 -0800617 CameraActivity.this.setFilmstripUiVisibility(false);
Angus Kongfaaee012013-12-07 00:38:46 -0800618 // When the user hide the filmstrip (either swipe out or
619 // tap on back key) we move to the first item so next time
620 // when the user swipe in the filmstrip, the most recent
621 // one is shown.
622 mFilmstripController.goToFirstItem();
Angus Kongfaaee012013-12-07 00:38:46 -0800623 }
624
625 @Override
626 public void onFilmstripShown() {
627 mFilmstripVisible = true;
Andy Huibers10c58162014-03-29 14:06:54 -0700628 UsageStatistics.instance().changeScreen(currentUserInterfaceMode(),
629 NavigationChange.InteractionCause.SWIPE_LEFT);
Angus Kongfaaee012013-12-07 00:38:46 -0800630 updateUiByData(mFilmstripController.getCurrentId());
Angus Kongfaaee012013-12-07 00:38:46 -0800631 }
632
Sascha Haeberling37f36112013-08-06 14:31:52 -0700633 @Override
Angus Kong26795a92014-02-20 09:18:09 -0800634 public void onFocusedDataLongPressed(int dataId) {
Sascha Haeberlingd114a772014-02-28 21:27:27 -0800635 // Do nothing.
Angus Kong26795a92014-02-20 09:18:09 -0800636 }
637
638 @Override
639 public void onFocusedDataPromoted(int dataID) {
Andy Huibers10c58162014-03-29 14:06:54 -0700640 UsageStatistics.instance().mediaInteraction(fileNameFromDataID(dataID),
641 MediaInteraction.InteractionType.DELETE,
Andy Huibersebd95372014-05-12 14:44:13 -0700642 NavigationChange.InteractionCause.SWIPE_UP, fileAgeFromDataID(dataID));
Sascha Haeberling37f36112013-08-06 14:31:52 -0700643 removeData(dataID);
644 }
Doris Liu6432cd62013-06-13 17:20:31 -0700645
Sascha Haeberling37f36112013-08-06 14:31:52 -0700646 @Override
Angus Kong26795a92014-02-20 09:18:09 -0800647 public void onFocusedDataDemoted(int dataID) {
Andy Huibers10c58162014-03-29 14:06:54 -0700648 UsageStatistics.instance().mediaInteraction(fileNameFromDataID(dataID),
649 MediaInteraction.InteractionType.DELETE,
Andy Huibersebd95372014-05-12 14:44:13 -0700650 NavigationChange.InteractionCause.SWIPE_DOWN,
651 fileAgeFromDataID(dataID));
Sascha Haeberling37f36112013-08-06 14:31:52 -0700652 removeData(dataID);
653 }
Doris Liu6432cd62013-06-13 17:20:31 -0700654
Sascha Haeberling37f36112013-08-06 14:31:52 -0700655 @Override
Angus Kong45671602014-01-13 15:06:17 -0800656 public void onEnterFullScreenUiShown(int dataId) {
657 if (mFilmstripVisible) {
658 CameraActivity.this.setFilmstripUiVisibility(true);
659 }
660 }
661
662 @Override
663 public void onLeaveFullScreenUiShown(int dataId) {
664 // Do nothing.
665 }
666
667 @Override
668 public void onEnterFullScreenUiHidden(int dataId) {
Angus Kongfaaee012013-12-07 00:38:46 -0800669 if (mFilmstripVisible) {
Angus Kongb2510252013-12-10 22:58:15 -0800670 CameraActivity.this.setFilmstripUiVisibility(false);
Erin Dahlgren3044d8c2013-10-10 18:23:45 -0700671 }
672 }
673
674 @Override
Angus Kong45671602014-01-13 15:06:17 -0800675 public void onLeaveFullScreenUiHidden(int dataId) {
Angus Kongfaaee012013-12-07 00:38:46 -0800676 // Do nothing.
677 }
Erin Dahlgren3044d8c2013-10-10 18:23:45 -0700678
Angus Kongfaaee012013-12-07 00:38:46 -0800679 @Override
680 public void onEnterFilmstrip(int dataId) {
681 if (mFilmstripVisible) {
Angus Kongb2510252013-12-10 22:58:15 -0800682 CameraActivity.this.setFilmstripUiVisibility(true);
Erin Dahlgren3044d8c2013-10-10 18:23:45 -0700683 }
684 }
685
686 @Override
Angus Kongfaaee012013-12-07 00:38:46 -0800687 public void onLeaveFilmstrip(int dataId) {
Angus Kong601c8c12014-02-21 10:01:58 -0800688 // Do nothing.
Angus Kongfaaee012013-12-07 00:38:46 -0800689 }
690
691 @Override
692 public void onDataReloaded() {
693 if (!mFilmstripVisible) {
694 return;
695 }
696 updateUiByData(mFilmstripController.getCurrentId());
697 }
698
699 @Override
Angus Kong8a2350a2013-12-16 15:02:34 -0800700 public void onDataUpdated(int dataId) {
701 if (!mFilmstripVisible) {
702 return;
703 }
704 updateUiByData(mFilmstripController.getCurrentId());
705 }
706
707 @Override
Angus Kongfaaee012013-12-07 00:38:46 -0800708 public void onEnterZoomView(int dataID) {
709 if (mFilmstripVisible) {
Angus Kongb2510252013-12-10 22:58:15 -0800710 CameraActivity.this.setFilmstripUiVisibility(false);
Angus Kongfaaee012013-12-07 00:38:46 -0800711 }
712 }
713
714 @Override
Andy Huibersc8924b22014-05-20 15:17:06 -0700715 public void onZoomAtIndexChanged(int dataId, float zoom) {
716 final LocalData localData = mDataAdapter.getLocalData(dataId);
717 long ageMillis = System.currentTimeMillis() - localData.getDateModified() * 1000;
718
719 // Do not log if items is to old or does not have a path (which is
720 // being used as a key).
721 if (TextUtils.isEmpty(localData.getPath()) ||
722 ageMillis > UsageStatistics.VIEW_TIMEOUT_MILLIS) {
723 return;
724 }
725 File localFile = new File(localData.getPath());
726 UsageStatistics.instance().mediaView(localFile.getName(),
727 TimeUnit.SECONDS.toMillis(localData.getDateModified()), zoom);
728 }
729
730 @Override
Angus Kongfaaee012013-12-07 00:38:46 -0800731 public void onDataFocusChanged(final int prevDataId, final int newDataId) {
732 if (!mFilmstripVisible) {
733 return;
Doris Liuaa874422013-09-18 19:43:12 -0700734 }
Angus Kong02cafdf2013-10-13 19:26:02 -0700735 // TODO: This callback is UI event callback, should always
736 // happen on UI thread. Find the reason for this
737 // runOnUiThread() and fix it.
Mangesh Ghiware33035c12013-08-23 13:28:21 -0700738 runOnUiThread(new Runnable() {
739 @Override
740 public void run() {
Angus Kongfaaee012013-12-07 00:38:46 -0800741 updateUiByData(newDataId);
ztenghui2c3d9a52013-09-03 11:27:21 -0700742 }
Mangesh Ghiware33035c12013-08-23 13:28:21 -0700743 });
Sascha Haeberling37f36112013-08-06 14:31:52 -0700744 }
Sam Juddde3e9ab2014-03-17 13:07:22 -0700745
746 @Override
747 public void onScroll(int firstVisiblePosition, int visibleItemCount, int totalItemCount) {
748 mPreloader.onScroll(null /*absListView*/, firstVisiblePosition, visibleItemCount, totalItemCount);
749 }
Sascha Haeberling37f36112013-08-06 14:31:52 -0700750 };
751
Sascha Haeberling44c1afb2013-12-20 11:59:35 -0800752 private final LocalDataAdapter.LocalDataListener mLocalDataListener =
Angus Konge2f4c032013-12-19 10:24:33 -0800753 new LocalDataAdapter.LocalDataListener() {
754 @Override
755 public void onMetadataUpdated(List<Integer> updatedData) {
Angus Kongcfe9acc2014-05-21 10:54:03 -0700756 if (mPaused) {
757 // Callback after the activity is paused.
758 return;
759 }
Angus Konge2f4c032013-12-19 10:24:33 -0800760 int currentDataId = mFilmstripController.getCurrentId();
761 for (Integer dataId : updatedData) {
762 if (dataId == currentDataId) {
763 updateBottomControlsByData(mDataAdapter.getLocalData(dataId));
Angus Kongcfe9acc2014-05-21 10:54:03 -0700764 // Currently we have only 1 data can be matched.
765 // No need to look for more, break.
766 break;
Angus Konge2f4c032013-12-19 10:24:33 -0800767 }
768 }
769 }
770 };
771
Sascha Haeberling4ed20592013-09-13 11:58:33 -0700772 public void gotoGallery() {
Sascha Haeberlinga83ec8a2014-03-31 13:22:17 -0700773 UsageStatistics.instance().changeScreen(NavigationChange.Mode.FILMSTRIP,
Andy Huibers10c58162014-03-29 14:06:54 -0700774 NavigationChange.InteractionCause.BUTTON);
Seth Raphaelcbd82672013-11-05 10:12:36 -0800775
Angus Kong62848152013-11-08 17:25:29 -0800776 mFilmstripController.goToNextItem();
Sascha Haeberling4ed20592013-09-13 11:58:33 -0700777 }
778
Sascha Haeberling5199c202013-09-05 17:10:19 -0700779 /**
Sascha Haeberling099b49b2014-04-08 07:08:46 -0700780 * If 'visible' is false, this hides the action bar. Also maintains
781 * lights-out at all times.
Sascha Haeberling846d3ab2014-02-04 12:48:55 +0100782 *
Sascha Haeberling099b49b2014-04-08 07:08:46 -0700783 * @param visible is false, this hides the action bar and filmstrip bottom
784 * controls.
Sascha Haeberling5199c202013-09-05 17:10:19 -0700785 */
Angus Kong601c8c12014-02-21 10:01:58 -0800786 private void setFilmstripUiVisibility(boolean visible) {
Sascha Haeberling099b49b2014-04-08 07:08:46 -0700787 mLightsOutRunnable.run();
Angus Kongb2510252013-12-10 22:58:15 -0800788 mCameraAppUI.getFilmstripBottomControls().setVisible(visible);
Angus Kong001dc312014-02-27 16:58:11 -0800789 if (visible != mActionBar.isShowing()) {
Doris Liuaa874422013-09-18 19:43:12 -0700790 if (visible) {
791 mActionBar.show();
Spike Spragueba97d192014-08-19 15:33:45 -0700792 mCameraAppUI.showBottomControls();
Doris Liuaa874422013-09-18 19:43:12 -0700793 } else {
794 mActionBar.hide();
Spike Spragueba97d192014-08-19 15:33:45 -0700795 mCameraAppUI.hideBottomControls();
Doris Liuaa874422013-09-18 19:43:12 -0700796 }
Doris Liuaa874422013-09-18 19:43:12 -0700797 }
Sascha Haeberling2d11fcf2014-03-13 09:04:32 -0700798 mFilmstripCoversPreview = visible;
799 updatePreviewVisibility();
Sascha Haeberling5199c202013-09-05 17:10:19 -0700800 }
801
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800802 private void hideSessionProgress() {
Angus Kong001dc312014-02-27 16:58:11 -0800803 mCameraAppUI.getFilmstripBottomControls().hideProgress();
Sascha Haeberling37f36112013-08-06 14:31:52 -0700804 }
805
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800806 private void showSessionProgress(CharSequence message) {
Sascha Haeberling099b49b2014-04-08 07:08:46 -0700807 CameraAppUI.BottomPanel controls = mCameraAppUI.getFilmstripBottomControls();
Angus Kong7ae25c22014-02-25 10:37:39 -0800808 controls.setProgressText(message);
Angus Kong001dc312014-02-27 16:58:11 -0800809 controls.hideControls();
Sascha Haeberling597c1a02014-03-06 11:46:06 -0800810 controls.hideProgressError();
Angus Kong7ae25c22014-02-25 10:37:39 -0800811 controls.showProgress();
Sascha Haeberling37f36112013-08-06 14:31:52 -0700812 }
813
Sascha Haeberling597c1a02014-03-06 11:46:06 -0800814 private void showProcessError(CharSequence message) {
815 mCameraAppUI.getFilmstripBottomControls().showProgressError(message);
816 }
817
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800818 private void updateSessionProgress(int progress) {
Angus Kong7ae25c22014-02-25 10:37:39 -0800819 mCameraAppUI.getFilmstripBottomControls().setProgress(progress);
Sascha Haeberling37f36112013-08-06 14:31:52 -0700820 }
Doris Liu6432cd62013-06-13 17:20:31 -0700821
Carlos Hernandezcbd058a2014-03-25 12:26:19 -0700822 private void updateSessionProgressText(CharSequence message) {
823 mCameraAppUI.getFilmstripBottomControls().setProgressText(message);
824 }
825
Mangesh Ghiwarea5682ab2013-09-19 09:24:23 -0700826 @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
827 private void setupNfcBeamPush() {
Sascha Haeberling846d3ab2014-02-04 12:48:55 +0100828 NfcAdapter adapter = NfcAdapter.getDefaultAdapter(mAppContext);
Mangesh Ghiwarea5682ab2013-09-19 09:24:23 -0700829 if (adapter == null) {
830 return;
831 }
832
833 if (!ApiHelper.HAS_SET_BEAM_PUSH_URIS) {
834 // Disable beaming
835 adapter.setNdefPushMessage(null, CameraActivity.this);
836 return;
837 }
838
839 adapter.setBeamPushUris(null, CameraActivity.this);
840 adapter.setBeamPushUrisCallback(new CreateBeamUrisCallback() {
841 @Override
842 public Uri[] createBeamUris(NfcEvent event) {
843 return mNfcPushUris;
844 }
845 }, CameraActivity.this);
846 }
847
Doris Liuaa874422013-09-18 19:43:12 -0700848 @Override
Seth Raphaelcbd82672013-11-05 10:12:36 -0800849 public boolean onShareTargetSelected(ShareActionProvider shareActionProvider, Intent intent) {
Angus Kong62848152013-11-08 17:25:29 -0800850 int currentDataId = mFilmstripController.getCurrentId();
Seth Raphaelcbd82672013-11-05 10:12:36 -0800851 if (currentDataId < 0) {
852 return false;
853 }
Andy Huibers10c58162014-03-29 14:06:54 -0700854 UsageStatistics.instance().mediaInteraction(fileNameFromDataID(currentDataId),
855 MediaInteraction.InteractionType.SHARE,
Andy Huibersebd95372014-05-12 14:44:13 -0700856 NavigationChange.InteractionCause.BUTTON, fileAgeFromDataID(currentDataId));
Sascha Haeberling846d3ab2014-02-04 12:48:55 +0100857 // TODO add intent.getComponent().getPackageName()
Seth Raphaelcbd82672013-11-05 10:12:36 -0800858 return true;
859 }
860
Sascha Haeberling14ff6c82013-12-13 13:29:58 -0800861 // Note: All callbacks come back on the main thread.
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800862 private final SessionListener mSessionListener =
863 new SessionListener() {
Ruben Brunk7cfcafd2013-10-17 15:41:44 -0700864 @Override
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800865 public void onSessionQueued(final Uri uri) {
Sam Judd8aa15492014-07-07 10:40:12 -0700866 Log.v(TAG, "onSessionQueued: " + uri);
Angus Kong571a8c32014-03-13 12:53:03 -0700867 if (!Storage.isSessionUri(uri)) {
868 return;
869 }
870 LocalSessionData newData = new LocalSessionData(uri);
871 mDataAdapter.addData(newData);
Angus Kong6798c342013-07-16 15:14:58 -0700872 }
873
874 @Override
Angus Kong571a8c32014-03-13 12:53:03 -0700875 public void onSessionDone(final Uri sessionUri) {
876 Log.v(TAG, "onSessionDone:" + sessionUri);
877 Uri contentUri = Storage.getContentUriForSessionUri(sessionUri);
878 if (contentUri == null) {
879 mDataAdapter.refresh(sessionUri);
880 return;
881 }
882 LocalData newData = LocalMediaData.PhotoData.fromContentUri(
883 getContentResolver(), contentUri);
884
Sascha Haeberlingaa52b3d2014-07-01 12:30:30 -0700885 // This can be null if e.g. a session is canceled (e.g.
886 // through discard panorama). It might be worth adding
887 // onSessionCanceled or the like this interface.
888 if (newData == null) {
889 Log.i(TAG, "onSessionDone: Could not find LocalData for URI: " + contentUri);
890 return;
891 }
892
Angus Kong571a8c32014-03-13 12:53:03 -0700893 final int pos = mDataAdapter.findDataByContentUri(sessionUri);
894 if (pos == -1) {
Sascha Haeberling099b49b2014-04-08 07:08:46 -0700895 // We do not have a placeholder for this image, perhaps
896 // due to the activity crashing or being killed.
Angus Kong571a8c32014-03-13 12:53:03 -0700897 mDataAdapter.addData(newData);
Sascha Haeberling099b49b2014-04-08 07:08:46 -0700898 } else {
Angus Kong571a8c32014-03-13 12:53:03 -0700899 mDataAdapter.updateData(pos, newData);
900 }
Angus Kong6798c342013-07-16 15:14:58 -0700901 }
902
903 @Override
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -0800904 public void onSessionProgress(final Uri uri, final int progress) {
905 if (progress < 0) {
906 // Do nothing, there is no task for this URI.
907 return;
908 }
Sascha Haeberling14ff6c82013-12-13 13:29:58 -0800909 int currentDataId = mFilmstripController.getCurrentId();
910 if (currentDataId == -1) {
911 return;
912 }
913 if (uri.equals(
Angus Kong571a8c32014-03-13 12:53:03 -0700914 mDataAdapter.getLocalData(currentDataId).getUri())) {
Sascha Haeberling14ff6c82013-12-13 13:29:58 -0800915 updateSessionProgress(progress);
916 }
917 }
918
919 @Override
Carlos Hernandezcbd058a2014-03-25 12:26:19 -0700920 public void onSessionProgressText(final Uri uri, final CharSequence message) {
921 int currentDataId = mFilmstripController.getCurrentId();
922 if (currentDataId == -1) {
923 return;
924 }
925 if (uri.equals(
926 mDataAdapter.getLocalData(currentDataId).getUri())) {
927 updateSessionProgressText(message);
928 }
929 }
930
931 @Override
Sascha Haeberling14ff6c82013-12-13 13:29:58 -0800932 public void onSessionUpdated(Uri uri) {
Sam Judd8aa15492014-07-07 10:40:12 -0700933 Log.v(TAG, "onSessionUpdated: " + uri);
Seth Raphael455ba5a2014-02-13 15:10:06 -0800934 mDataAdapter.refresh(uri);
Angus Kong6798c342013-07-16 15:14:58 -0700935 }
Sascha Haeberling597c1a02014-03-06 11:46:06 -0800936
937 @Override
Angus Kong571a8c32014-03-13 12:53:03 -0700938 public void onSessionPreviewAvailable(Uri uri) {
Sam Judd8aa15492014-07-07 10:40:12 -0700939 Log.v(TAG, "onSessionPreviewAvailable: " + uri);
Angus Kong571a8c32014-03-13 12:53:03 -0700940 mDataAdapter.refresh(uri);
941 int dataId = mDataAdapter.findDataByContentUri(uri);
942 if (dataId != -1) {
Spike Sprague159e6e92014-05-27 18:26:30 -0700943 startPeekAnimation(mDataAdapter.getLocalData(dataId),
944 mCurrentModule.getPeekAccessibilityString());
Angus Kong571a8c32014-03-13 12:53:03 -0700945 }
946 }
947
948 @Override
Sascha Haeberling597c1a02014-03-06 11:46:06 -0800949 public void onSessionFailed(Uri uri, CharSequence reason) {
950 Log.v(TAG, "onSessionFailed:" + uri);
951
952 int failedDataId = mDataAdapter.findDataByContentUri(uri);
953 int currentDataId = mFilmstripController.getCurrentId();
954
955 if (currentDataId == failedDataId) {
956 updateSessionProgress(0);
957 showProcessError(reason);
958 }
Seth Raphael455ba5a2014-02-13 15:10:06 -0800959 // HERE
960 mDataAdapter.refresh(uri);
Sascha Haeberling597c1a02014-03-06 11:46:06 -0800961 }
Angus Kong6798c342013-07-16 15:14:58 -0700962 };
963
Angus Kong9f1db522013-11-09 16:25:59 -0800964 @Override
965 public Context getAndroidContext() {
Sascha Haeberling846d3ab2014-02-04 12:48:55 +0100966 return mAppContext;
Angus Kong9f1db522013-11-09 16:25:59 -0800967 }
968
969 @Override
Angus Kong0eaf0162013-12-16 15:53:30 -0800970 public void launchActivityByIntent(Intent intent) {
Senpo Hu9f2b20a2014-08-29 16:27:03 -0700971 // Starting from L, we prefer not to start edit activity within camera's task.
972 mResetToPreviewOnResume = false;
973 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
974
975 startActivity(intent);
Angus Kong0eaf0162013-12-16 15:53:30 -0800976 }
977
978 @Override
Doris Liuf55f3c42013-11-20 00:24:46 -0800979 public int getCurrentModuleIndex() {
980 return mCurrentModeIndex;
981 }
982
983 @Override
Erin Dahlgren6190c362014-06-13 14:12:08 -0700984 public int getCurrentCameraId() {
985 return mCameraController.getCurrentCameraId();
986 }
987
988 @Override
989 public String getModuleScope() {
990 return MODULE_SCOPE_PREFIX + mCurrentModule.getModuleStringIdentifier();
991 }
992
993 @Override
994 public String getCameraScope() {
Alan Newberger62c20bf2014-07-22 18:46:41 -0700995 int currentCameraId = getCurrentCameraId();
996 if (currentCameraId < 0) {
997 // if an unopen camera i.e. negative ID is returned, which we've observed in
998 // some automated scenarios, just return it as a valid separate scope
999 // this could cause user issues, so log a stack trace noting the call path
1000 // which resulted in this scenario.
1001 Log.w(TAG, "getting camera scope with no open camera, using id: " + currentCameraId,
1002 new Exception());
Erin Dahlgren6190c362014-06-13 14:12:08 -07001003 }
Alan Newberger62c20bf2014-07-22 18:46:41 -07001004 return CAMERA_SCOPE_PREFIX + Integer.toString(currentCameraId);
Erin Dahlgren6190c362014-06-13 14:12:08 -07001005 }
1006
1007 @Override
Erin Dahlgren0a6a8d82014-01-09 22:17:38 -08001008 public ModuleController getCurrentModuleController() {
Sascha Haeberling8793eff2014-01-15 16:33:59 -08001009 return mCurrentModule;
Erin Dahlgren0a6a8d82014-01-09 22:17:38 -08001010 }
1011
1012 @Override
Doris Liubd1b8f92014-01-03 17:59:51 -08001013 public int getQuickSwitchToModuleId(int currentModuleIndex) {
Sascha Haeberling846d3ab2014-02-04 12:48:55 +01001014 return mModuleManager.getQuickSwitchToModuleId(currentModuleIndex, mSettingsManager,
1015 mAppContext);
Doris Liubd1b8f92014-01-03 17:59:51 -08001016 }
1017
1018 @Override
Angus Kong9f1db522013-11-09 16:25:59 -08001019 public SurfaceTexture getPreviewBuffer() {
1020 // TODO: implement this
1021 return null;
1022 }
1023
1024 @Override
Doris Liu5a367542014-01-17 17:21:42 -08001025 public void onPreviewReadyToStart() {
1026 mCameraAppUI.onPreviewReadyToStart();
1027 }
1028
1029 @Override
Doris Liu2b906b82013-12-10 16:34:08 -08001030 public void onPreviewStarted() {
1031 mCameraAppUI.onPreviewStarted();
1032 }
1033
1034 @Override
Doris Liu482de022013-12-18 19:18:16 -08001035 public void addPreviewAreaSizeChangedListener(
Angus Kong2bacca72014-03-06 12:57:29 -08001036 PreviewStatusListener.PreviewAreaChangedListener listener) {
1037 mCameraAppUI.addPreviewAreaChangedListener(listener);
Doris Liu482de022013-12-18 19:18:16 -08001038 }
1039
1040 @Override
1041 public void removePreviewAreaSizeChangedListener(
Angus Kong2bacca72014-03-06 12:57:29 -08001042 PreviewStatusListener.PreviewAreaChangedListener listener) {
1043 mCameraAppUI.removePreviewAreaChangedListener(listener);
Doris Liu482de022013-12-18 19:18:16 -08001044 }
1045
1046 @Override
Doris Liu4d4a4bc2013-12-19 18:55:54 -08001047 public void setupOneShotPreviewListener() {
1048 mCameraController.setOneShotPreviewCallback(mMainHandler,
Sol Boucher5a344962014-06-17 14:05:08 -07001049 new CameraAgent.CameraPreviewDataCallback() {
Doris Liu482de022013-12-18 19:18:16 -08001050 @Override
Sol Boucher5a344962014-06-17 14:05:08 -07001051 public void onPreviewFrame(byte[] data, CameraAgent.CameraProxy camera) {
Sameer Padaladb81ce62014-03-21 15:33:56 -07001052 mCurrentModule.onPreviewInitialDataReceived();
Doris Liu482de022013-12-18 19:18:16 -08001053 mCameraAppUI.onNewPreviewFrame();
1054 }
Angus Kong2bca2102014-03-11 16:27:30 -07001055 }
1056 );
Doris Liu4d4a4bc2013-12-19 18:55:54 -08001057 }
1058
1059 @Override
Doris Liu70da9182013-12-17 18:41:15 -08001060 public void updatePreviewAspectRatio(float aspectRatio) {
1061 mCameraAppUI.updatePreviewAspectRatio(aspectRatio);
1062 }
1063
1064 @Override
Seth Raphael6382c702014-05-20 13:19:16 -07001065 public void updatePreviewTransformFullscreen(Matrix matrix, float aspectRatio) {
1066 mCameraAppUI.updatePreviewTransformFullscreen(matrix, aspectRatio);
Seth Raphael02c129a2014-05-19 21:46:04 -07001067 }
1068
1069 @Override
1070 public RectF getFullscreenRect() {
1071 return mCameraAppUI.getFullscreenRect();
1072 }
1073
1074 @Override
Doris Liu70da9182013-12-17 18:41:15 -08001075 public void updatePreviewTransform(Matrix matrix) {
1076 mCameraAppUI.updatePreviewTransform(matrix);
1077 }
1078
1079 @Override
Doris Liu06db7422013-12-09 19:36:25 -08001080 public void setPreviewStatusListener(PreviewStatusListener previewStatusListener) {
1081 mCameraAppUI.setPreviewStatusListener(previewStatusListener);
1082 }
1083
1084 @Override
Angus Kong9f1db522013-11-09 16:25:59 -08001085 public FrameLayout getModuleLayoutRoot() {
Doris Liuc6c97402013-12-06 21:02:53 -08001086 return mCameraAppUI.getModuleRootView();
Angus Kong9f1db522013-11-09 16:25:59 -08001087 }
1088
1089 @Override
1090 public void setShutterEventsListener(ShutterEventsListener listener) {
1091 // TODO: implement this
1092 }
1093
1094 @Override
1095 public void setShutterEnabled(boolean enabled) {
Erin Dahlgren667630d2014-04-01 14:03:25 -07001096 mCameraAppUI.setShutterButtonEnabled(enabled);
Angus Kong9f1db522013-11-09 16:25:59 -08001097 }
1098
1099 @Override
1100 public boolean isShutterEnabled() {
Erin Dahlgren667630d2014-04-01 14:03:25 -07001101 return mCameraAppUI.isShutterButtonEnabled();
Angus Kong9f1db522013-11-09 16:25:59 -08001102 }
1103
1104 @Override
1105 public void startPreCaptureAnimation() {
Doris Liu1dfe7822013-12-12 00:02:08 -08001106 mCameraAppUI.startPreCaptureAnimation();
Angus Kong9f1db522013-11-09 16:25:59 -08001107 }
1108
1109 @Override
1110 public void cancelPreCaptureAnimation() {
1111 // TODO: implement this
1112 }
1113
1114 @Override
1115 public void startPostCaptureAnimation() {
1116 // TODO: implement this
1117 }
1118
1119 @Override
1120 public void startPostCaptureAnimation(Bitmap thumbnail) {
1121 // TODO: implement this
1122 }
1123
1124 @Override
1125 public void cancelPostCaptureAnimation() {
1126 // TODO: implement this
1127 }
1128
1129 @Override
Angus Kong9f1db522013-11-09 16:25:59 -08001130 public OrientationManager getOrientationManager() {
1131 return mOrientationManager;
1132 }
1133
1134 @Override
1135 public LocationManager getLocationManager() {
Erin Dahlgren21c21a62013-11-19 16:37:38 -08001136 return mLocationManager;
Angus Kong9f1db522013-11-09 16:25:59 -08001137 }
1138
1139 @Override
1140 public void lockOrientation() {
Sascha Haeberlingba29a442014-02-26 16:43:19 -08001141 if (mOrientationManager != null) {
1142 mOrientationManager.lockOrientation();
1143 }
Angus Kong9f1db522013-11-09 16:25:59 -08001144 }
1145
1146 @Override
1147 public void unlockOrientation() {
Sascha Haeberlingba29a442014-02-26 16:43:19 -08001148 if (mOrientationManager != null) {
1149 mOrientationManager.unlockOrientation();
1150 }
Angus Kong9f1db522013-11-09 16:25:59 -08001151 }
1152
Angus Kong50521172014-01-17 17:23:59 -08001153 /**
1154 * Starts the filmstrip peek animation if the filmstrip is not visible.
1155 * Only {@link LocalData#LOCAL_IMAGE}, {@link
1156 * LocalData#LOCAL_IN_PROGRESS_DATA} and {@link
1157 * LocalData#LOCAL_VIDEO} are supported.
1158 *
1159 * @param data The data to peek.
Spike Sprague159e6e92014-05-27 18:26:30 -07001160 * @param accessibilityString Accessibility string to announce on peek animation.
Angus Kong50521172014-01-17 17:23:59 -08001161 */
Spike Sprague159e6e92014-05-27 18:26:30 -07001162 private void startPeekAnimation(final LocalData data, final String accessibilityString) {
Angus Kong50521172014-01-17 17:23:59 -08001163 if (mFilmstripVisible || mPeekAnimationHandler == null) {
1164 return;
1165 }
1166
1167 int dataType = data.getLocalDataType();
1168 if (dataType != LocalData.LOCAL_IMAGE && dataType != LocalData.LOCAL_IN_PROGRESS_DATA &&
1169 dataType != LocalData.LOCAL_VIDEO) {
1170 return;
1171 }
1172
Angus Kongc195e7a2014-02-20 16:56:37 -08001173 mPeekAnimationHandler.startDecodingJob(data, new Callback<Bitmap>() {
Angus Kong50521172014-01-17 17:23:59 -08001174 @Override
1175 public void onCallback(Bitmap result) {
Spike Sprague159e6e92014-05-27 18:26:30 -07001176 mCameraAppUI.startPeekAnimation(result, true, accessibilityString);
Angus Kong50521172014-01-17 17:23:59 -08001177 }
1178 });
1179 }
1180
Angus Kong9f1db522013-11-09 16:25:59 -08001181 @Override
Doris Liu6432cd62013-06-13 17:20:31 -07001182 public void notifyNewMedia(Uri uri) {
Sascha Haeberling08b3c942014-07-30 17:48:52 -07001183 // TODO: This method is running on the main thread. Also we should get
1184 // rid of that AsyncTask.
1185
Spike Spraguee6374b72014-04-25 17:24:32 -07001186 updateStorageSpaceAndHint(null);
Angus Kong571a8c32014-03-13 12:53:03 -07001187 ContentResolver cr = getContentResolver();
1188 String mimeType = cr.getType(uri);
Angus Kong810b0b62014-04-30 11:26:21 -07001189 LocalData newData = null;
Angus Kong571a8c32014-03-13 12:53:03 -07001190 if (LocalDataUtil.isMimeTypeVideo(mimeType)) {
1191 sendBroadcast(new Intent(CameraUtil.ACTION_NEW_VIDEO, uri));
Angus Kong810b0b62014-04-30 11:26:21 -07001192 newData = LocalMediaData.VideoData.fromContentUri(getContentResolver(), uri);
Angus Kong571a8c32014-03-13 12:53:03 -07001193 if (newData == null) {
1194 Log.e(TAG, "Can't find video data in content resolver:" + uri);
1195 return;
Seth Raphael455ba5a2014-02-13 15:10:06 -08001196 }
Angus Kong571a8c32014-03-13 12:53:03 -07001197 } else if (LocalDataUtil.isMimeTypeImage(mimeType)) {
1198 CameraUtil.broadcastNewPicture(mAppContext, uri);
Angus Kong810b0b62014-04-30 11:26:21 -07001199 newData = LocalMediaData.PhotoData.fromContentUri(getContentResolver(), uri);
Angus Kong571a8c32014-03-13 12:53:03 -07001200 if (newData == null) {
1201 Log.e(TAG, "Can't find photo data in content resolver:" + uri);
1202 return;
1203 }
Angus Kong571a8c32014-03-13 12:53:03 -07001204 } else {
Angus Kong2bca2102014-03-11 16:27:30 -07001205 Log.w(TAG, "Unknown new media with MIME type:" + mimeType + ", uri:" + uri);
Angus Kong810b0b62014-04-30 11:26:21 -07001206 return;
Doris Liu48239f42013-03-04 22:19:10 -08001207 }
Sascha Haeberling08b3c942014-07-30 17:48:52 -07001208
Angus Kong810b0b62014-04-30 11:26:21 -07001209 // We are preloading the metadata for new video since we need the
1210 // rotation info for the thumbnail.
1211 new AsyncTask<LocalData, Void, LocalData>() {
Angus Kong810b0b62014-04-30 11:26:21 -07001212 @Override
1213 protected LocalData doInBackground(LocalData... params) {
1214 LocalData data = params[0];
1215 MetadataLoader.loadMetadata(getAndroidContext(), data);
1216 return data;
1217 }
1218
1219 @Override
1220 protected void onPostExecute(LocalData data) {
Sascha Haeberling08b3c942014-07-30 17:48:52 -07001221 // TODO: Figure out why sometimes the data is aleady there.
1222 mDataAdapter.addData(data);
1223 startPeekAnimation(data, mCurrentModule.getPeekAccessibilityString());
Angus Kong810b0b62014-04-30 11:26:21 -07001224 }
1225 }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, newData);
Doris Liu48239f42013-03-04 22:19:10 -08001226 }
1227
Angus Kong20fad242013-11-11 18:23:46 -08001228 @Override
Angus Kong13e87c42013-11-25 10:02:47 -08001229 public void enableKeepScreenOn(boolean enabled) {
1230 if (mPaused) {
1231 return;
1232 }
1233
1234 mKeepScreenOn = enabled;
1235 if (mKeepScreenOn) {
1236 mMainHandler.removeMessages(MSG_CLEAR_SCREEN_ON_FLAG);
1237 getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
1238 } else {
1239 keepScreenOnForAWhile();
1240 }
1241 }
1242
1243 @Override
Angus Kong20fad242013-11-11 18:23:46 -08001244 public CameraProvider getCameraProvider() {
1245 return mCameraController;
1246 }
1247
Sascha Haeberling08b3c942014-07-30 17:48:52 -07001248 @Override
1249 public OneCameraManager getCameraManager() {
1250 return OneCameraManager.get(this);
1251 }
1252
Doris Liu6432cd62013-06-13 17:20:31 -07001253 private void removeData(int dataID) {
Sascha Haeberling44c1afb2013-12-20 11:59:35 -08001254 mDataAdapter.removeData(dataID);
Doris Liu742cd5b2013-09-12 16:17:43 -07001255 if (mDataAdapter.getTotalNumber() > 1) {
1256 showUndoDeletionBar();
1257 } else {
1258 // If camera preview is the only view left in filmstrip,
1259 // no need to show undo bar.
Doris Liuf2c14332013-09-26 11:24:37 -07001260 mPendingDeletion = true;
Doris Liu742cd5b2013-09-12 16:17:43 -07001261 performDeletion();
Angus Kong1f9db2d2014-01-09 00:56:35 -08001262 if (mFilmstripVisible) {
1263 mCameraAppUI.getFilmstripContentPanel().animateHide();
1264 }
Doris Liu742cd5b2013-09-12 16:17:43 -07001265 }
Michael Kolb8872c232013-01-29 10:33:22 -08001266 }
1267
ztenghui0353ca22013-08-13 13:53:16 -07001268 @Override
1269 public boolean onOptionsItemSelected(MenuItem item) {
1270 // Handle presses on the action bar items
1271 switch (item.getItemId()) {
Alan Newberger3f969c12013-08-23 10:10:30 -07001272 case android.R.id.home:
Angus Kong6c0c7f12014-01-15 14:40:27 -08001273 onBackPressed();
Angus Kong248f42b2013-12-06 15:49:17 -08001274 return true;
Sascha Haeberlingd114a772014-02-28 21:27:27 -08001275 case R.id.action_details:
1276 showDetailsDialog(mFilmstripController.getCurrentId());
1277 return true;
Erin Dahlgren26a4bb92014-06-27 11:18:36 -07001278 case R.id.action_help_and_feedback:
1279 mResetToPreviewOnResume = false;
1280 GoogleHelpHelper.launchGoogleHelp(this);
1281 return true;
ztenghui0353ca22013-08-13 13:53:16 -07001282 default:
1283 return super.onOptionsItemSelected(item);
1284 }
1285 }
1286
ztenghuifd43e3b2013-09-03 11:30:11 -07001287 private boolean isCaptureIntent() {
1288 if (MediaStore.ACTION_VIDEO_CAPTURE.equals(getIntent().getAction())
1289 || MediaStore.ACTION_IMAGE_CAPTURE.equals(getIntent().getAction())
1290 || MediaStore.ACTION_IMAGE_CAPTURE_SECURE.equals(getIntent().getAction())) {
1291 return true;
1292 } else {
1293 return false;
1294 }
1295 }
1296
Sol Boucher5a344962014-06-17 14:05:08 -07001297 private final CameraAgent.CameraExceptionCallback mCameraDefaultExceptionCallback
1298 = new CameraAgent.CameraExceptionCallback() {
Erin Dahlgren630d55b2014-03-10 14:40:59 -07001299 @Override
1300 public void onCameraException(RuntimeException e) {
Alan Newbergerd41766f2014-04-09 18:25:34 -07001301 Log.e(TAG, "Camera Exception", e);
Erin Dahlgren630d55b2014-03-10 14:40:59 -07001302 CameraUtil.showErrorAndFinish(CameraActivity.this,
1303 R.string.cannot_connect_camera);
1304 }
1305 };
Sascha Haeberlingd114a772014-02-28 21:27:27 -08001306
ztenghui0353ca22013-08-13 13:53:16 -07001307 @Override
Doris Liu6432cd62013-06-13 17:20:31 -07001308 public void onCreate(Bundle state) {
Doris Liu7cbecee2014-01-30 12:29:27 -08001309 CameraPerformanceTracker.onEvent(CameraPerformanceTracker.ACTIVITY_START);
Doris Liu6432cd62013-06-13 17:20:31 -07001310 super.onCreate(state);
Sam Judd632eaaf2014-06-24 13:31:02 -07001311 if (!Glide.isSetup()) {
1312 Glide.setup(new GlideBuilder(this)
1313 .setResizeService(new FifoPriorityThreadPoolExecutor(1)));
1314 Glide.get(this).setMemoryCategory(MemoryCategory.HIGH);
Sam Judd4021c892014-03-17 12:57:50 -07001315 }
Erin Dahlgren6ee33342014-04-02 09:48:42 -07001316
Kevin Gabayana0e83472014-01-15 15:21:13 -08001317 mOnCreateTime = System.currentTimeMillis();
Sascha Haeberling846d3ab2014-02-04 12:48:55 +01001318 mAppContext = getApplicationContext();
Sascha Haeberling2d4be252014-08-27 17:56:08 -07001319 mSoundPlayer = new SoundPlayer(mAppContext);
Erin Dahlgren6190c362014-06-13 14:12:08 -07001320
1321 // TODO: Try to move all the resources allocation to happen as soon as
1322 // possible so we can call module.init() at the earliest time.
1323 mModuleManager = new ModuleManagerImpl();
Sascha Haeberling048bf4d2013-10-06 17:49:51 -07001324 GcamHelper.init(getContentResolver());
Erin Dahlgren6190c362014-06-13 14:12:08 -07001325 ModulesInfo.setupModules(mAppContext, mModuleManager);
1326
Alan Newberger39529582014-07-17 09:55:34 -07001327 mSettingsManager = getServices().getSettingsManager();
Alan Newberger2307b602014-08-05 09:56:17 -07001328 AppUpgrader appUpgrader = new AppUpgrader(this);
1329 appUpgrader.upgrade(mSettingsManager);
Erin Dahlgren6190c362014-06-13 14:12:08 -07001330 Keys.setDefaults(mSettingsManager, mAppContext);
Sascha Haeberling048bf4d2013-10-06 17:49:51 -07001331
ztenghui50df4702013-08-13 15:53:57 -07001332 getWindow().requestFeature(Window.FEATURE_ACTION_BAR);
Doris Liu1c94b7d2013-11-09 19:13:44 -08001333 setContentView(R.layout.activity_main);
Spike Sprague4f93e192014-08-19 18:53:41 -07001334
ztenghuifa9e2cc2013-08-09 17:37:15 -07001335 mActionBar = getActionBar();
Spike Sprague4cc78bb2014-08-21 10:16:10 -07001336 // set actionbar background to complete transparent
1337 mActionBar.setBackgroundDrawable(new ColorDrawable(0x00000000));
Spike Spragueba97d192014-08-19 15:33:45 -07001338 mActionBar.addOnMenuVisibilityListener(mOnMenuVisibilityListener);
Spike Sprague4cc78bb2014-08-21 10:16:10 -07001339
Sascha Haeberling846d3ab2014-02-04 12:48:55 +01001340 mMainHandler = new MainHandler(this, getMainLooper());
Sol Boucher44ce4b22014-08-04 23:41:38 -07001341 mCameraController = new CameraController(mAppContext, this, mMainHandler,
1342 CameraAgentFactory.getAndroidCameraAgent(this, CameraAgentFactory.CameraApi.API_1),
1343 CameraAgentFactory.getAndroidCameraAgent(this, CameraAgentFactory.CameraApi.AUTO));
Erin Dahlgren630d55b2014-03-10 14:40:59 -07001344 mCameraController.setCameraDefaultExceptionCallback(mCameraDefaultExceptionCallback,
1345 mMainHandler);
1346
Doris Liu70576b62013-11-14 20:30:33 -08001347 mModeListView = (ModeListView) findViewById(R.id.mode_list_layout);
Doris Liua20074f2013-12-09 15:19:06 -08001348 mModeListView.init(mModuleManager.getSupportedModeIndexList());
Michael Kolb08650182013-02-25 19:43:56 -08001349 if (ApiHelper.HAS_ROTATION_ANIMATION) {
Doris Liu6432cd62013-06-13 17:20:31 -07001350 setRotationAnimation();
Michael Kolb08650182013-02-25 19:43:56 -08001351 }
Sascha Haeberling8c1a9222014-02-25 09:38:06 -08001352 mModeListView.setVisibilityChangedListener(new ModeListVisibilityChangedListener() {
1353 @Override
1354 public void onVisibilityChanged(boolean visible) {
Sascha Haeberling2d11fcf2014-03-13 09:04:32 -07001355 mModeListVisible = visible;
Spike Spragueb7e41a72014-07-07 15:13:27 -07001356 mCameraAppUI.setShutterButtonImportantToA11y(!visible);
Sascha Haeberling2d11fcf2014-03-13 09:04:32 -07001357 updatePreviewVisibility();
Sascha Haeberling8c1a9222014-02-25 09:38:06 -08001358 }
1359 });
Doris Liuaa874422013-09-18 19:43:12 -07001360
Doris Liu6432cd62013-06-13 17:20:31 -07001361 // Check if this is in the secure camera mode.
1362 Intent intent = getIntent();
1363 String action = intent.getAction();
Doris Liub84b9732013-06-18 17:14:26 -07001364 if (INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE.equals(action)
1365 || ACTION_IMAGE_CAPTURE_SECURE.equals(action)) {
Doris Liu6432cd62013-06-13 17:20:31 -07001366 mSecureCamera = true;
1367 } else {
1368 mSecureCamera = intent.getBooleanExtra(SECURE_CAMERA_EXTRA, false);
1369 }
Doris Liub84b9732013-06-18 17:14:26 -07001370
1371 if (mSecureCamera) {
Sascha Haeberling846d3ab2014-02-04 12:48:55 +01001372 // Change the window flags so that secure camera can show when
1373 // locked
Doris Liub84b9732013-06-18 17:14:26 -07001374 Window win = getWindow();
1375 WindowManager.LayoutParams params = win.getAttributes();
1376 params.flags |= WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
1377 win.setAttributes(params);
1378
Sascha Haeberling846d3ab2014-02-04 12:48:55 +01001379 // Filter for screen off so that we can finish secure camera
1380 // activity
Doris Liub84b9732013-06-18 17:14:26 -07001381 // when screen is off.
Doris Liu6432cd62013-06-13 17:20:31 -07001382 IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_OFF);
1383 registerReceiver(mScreenOffReceiver, filter);
Doris Liub84b9732013-06-18 17:14:26 -07001384 }
Angus Kongb2510252013-12-10 22:58:15 -08001385 mCameraAppUI = new CameraAppUI(this,
Sascha Haeberling8793eff2014-01-15 16:33:59 -08001386 (MainActivityLayout) findViewById(R.id.activity_root_view), isCaptureIntent());
Angus Kongb2510252013-12-10 22:58:15 -08001387
1388 mCameraAppUI.setFilmstripBottomControlsListener(mMyFilmstripBottomControlListener);
1389
Angus Kong653c43b2013-08-21 18:28:43 -07001390 mAboveFilmstripControlLayout =
Angus Kongb95699e2013-12-07 13:52:51 -08001391 (FrameLayout) findViewById(R.id.camera_filmstrip_content_layout);
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001392
Sascha Haeberling846d3ab2014-02-04 12:48:55 +01001393 // Add the session listener so we can track the session progress
1394 // updates.
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08001395 getServices().getCaptureSessionManager().addSessionListener(mSessionListener);
Angus Kong62848152013-11-08 17:25:29 -08001396 mFilmstripController = ((FilmstripView) findViewById(R.id.filmstrip_view)).getController();
Angus Kongfaaee012013-12-07 00:38:46 -08001397 mFilmstripController.setImageGap(
Doris Liu6432cd62013-06-13 17:20:31 -07001398 getResources().getDimensionPixelSize(R.dimen.camera_film_strip_gap));
Sascha Haeberlingf1f51862013-07-31 11:28:21 -07001399 mPanoramaViewHelper = new PanoramaViewHelper(this);
1400 mPanoramaViewHelper.onCreate();
Doris Liu6432cd62013-06-13 17:20:31 -07001401 // Set up the camera preview first so the preview shows up ASAP.
Sam Judd4021c892014-03-17 12:57:50 -07001402 mDataAdapter = new CameraDataAdapter(mAppContext, R.color.photo_placeholder);
Angus Konge2f4c032013-12-19 10:24:33 -08001403 mDataAdapter.setLocalDataListener(mLocalDataListener);
Angus Kongfaaee012013-12-07 00:38:46 -08001404
Sam Juddde3e9ab2014-03-17 13:07:22 -07001405 mPreloader = new Preloader<Integer, AsyncTask>(FILMSTRIP_PRELOAD_AHEAD_ITEMS, mDataAdapter,
1406 mDataAdapter);
1407
Spike Sprague0f3c4b42013-12-10 19:50:17 -08001408 mCameraAppUI.getFilmstripContentPanel().setFilmstripListener(mFilmstripListener);
Erin Dahlgren6190c362014-06-13 14:12:08 -07001409 if (mSettingsManager.getBoolean(SettingsManager.SCOPE_GLOBAL,
1410 Keys.KEY_SHOULD_SHOW_REFOCUS_VIEWER_CLING)) {
Doris Liue7d7b9e2014-03-31 15:27:40 -07001411 mCameraAppUI.setupClingForViewer(CameraAppUI.BottomPanel.VIEWER_REFOCUS);
1412 }
Sascha Haeberling2654dd92013-08-28 15:28:57 -07001413
Sascha Haeberling846d3ab2014-02-04 12:48:55 +01001414 mLocationManager = new LocationManager(mAppContext);
Erin Dahlgren357b7672013-11-20 17:38:14 -08001415
Erin Dahlgren357b7672013-11-20 17:38:14 -08001416 mOrientationManager = new OrientationManagerImpl(this);
1417 mOrientationManager.addOnOrientationChangeListener(mMainHandler, this);
Erin Dahlgrenc120b0f2013-11-19 10:53:49 -08001418
Erin Dahlgren4e0a4642014-03-31 13:54:30 -07001419 setModuleFromModeIndex(getModeIndex());
Erin Dahlgrend8de0772014-02-03 10:12:27 -08001420 mCameraAppUI.prepareModuleUI();
Angus Kong13e87c42013-11-25 10:02:47 -08001421 mCurrentModule.init(this, isSecureCamera(), isCaptureIntent());
Sascha Haeberling37f36112013-08-06 14:31:52 -07001422
1423 if (!mSecureCamera) {
Angus Kong62848152013-11-08 17:25:29 -08001424 mFilmstripController.setDataAdapter(mDataAdapter);
Angus Konga7194602013-09-06 17:20:15 -07001425 if (!isCaptureIntent()) {
Sascha Haeberlingadde93f2014-03-31 16:58:11 -07001426 mDataAdapter.requestLoad(new Callback<Void>() {
1427 @Override
1428 public void onCallback(Void result) {
1429 fillTemporarySessions();
1430 }
1431 });
Angus Konga7194602013-09-06 17:20:15 -07001432 }
Sascha Haeberling37f36112013-08-06 14:31:52 -07001433 } else {
Sascha Haeberlinga5a08d72013-09-11 20:30:52 -07001434 // Put a lock placeholder as the last image by setting its date to
1435 // 0.
Sascha Haeberling37f36112013-08-06 14:31:52 -07001436 ImageView v = (ImageView) getLayoutInflater().inflate(
1437 R.layout.secure_album_placeholder, null);
Spike Spraguea93ba0d2014-05-21 12:13:51 -07001438 v.setTag(R.id.mediadata_tag_viewtype, LocalDataViewType.SECURE_ALBUM_PLACEHOLDER.ordinal());
Angus Kong690dc472013-09-21 14:48:51 -07001439 v.setOnClickListener(new View.OnClickListener() {
1440 @Override
1441 public void onClick(View view) {
Sascha Haeberlinga83ec8a2014-03-31 13:22:17 -07001442 UsageStatistics.instance().changeScreen(NavigationChange.Mode.GALLERY,
Andy Huibers10c58162014-03-29 14:06:54 -07001443 NavigationChange.InteractionCause.BUTTON);
Angus Kongd3de1712013-12-12 22:01:12 -08001444 startGallery();
Angus Kong690dc472013-09-21 14:48:51 -07001445 finish();
1446 }
1447 });
Alan Newberger62c6d862014-03-26 11:49:46 -07001448 v.setContentDescription(getString(R.string.accessibility_unlock_to_camera));
Sascha Haeberling37f36112013-08-06 14:31:52 -07001449 mDataAdapter = new FixedLastDataAdapter(
Sascha Haeberling846d3ab2014-02-04 12:48:55 +01001450 mAppContext,
Angus Kong166e36f2013-12-03 08:54:42 -08001451 mDataAdapter,
Angus Kongbd260692013-08-07 14:52:56 -07001452 new SimpleViewData(
Sascha Haeberling37f36112013-08-06 14:31:52 -07001453 v,
Sam Judd43bf03f2014-03-17 11:27:03 -07001454 LocalDataViewType.SECURE_ALBUM_PLACEHOLDER,
Sascha Haeberling37f36112013-08-06 14:31:52 -07001455 v.getDrawable().getIntrinsicWidth(),
1456 v.getDrawable().getIntrinsicHeight(),
1457 0, 0));
1458 // Flush out all the original data.
1459 mDataAdapter.flush();
Angus Kong62848152013-11-08 17:25:29 -08001460 mFilmstripController.setDataAdapter(mDataAdapter);
Sascha Haeberling37f36112013-08-06 14:31:52 -07001461 }
Mangesh Ghiwarea5682ab2013-09-19 09:24:23 -07001462
1463 setupNfcBeamPush();
ztenghui064d6002013-09-05 15:47:58 -07001464
Doris Liu2b86d872013-09-26 15:23:41 -07001465 mLocalImagesObserver = new LocalMediaObserver();
1466 mLocalVideosObserver = new LocalMediaObserver();
ztenghui064d6002013-09-05 15:47:58 -07001467
1468 getContentResolver().registerContentObserver(
1469 MediaStore.Images.Media.EXTERNAL_CONTENT_URI, true,
1470 mLocalImagesObserver);
1471 getContentResolver().registerContentObserver(
1472 MediaStore.Video.Media.EXTERNAL_CONTENT_URI, true,
1473 mLocalVideosObserver);
Kevin Gabayan0aeb0c82014-04-08 11:12:05 -07001474 mMemoryManager = getServices().getMemoryManager();
Kevin Gabayan05ee74d2014-04-08 16:25:23 -07001475
1476 AsyncTask.THREAD_POOL_EXECUTOR.execute(new Runnable() {
Sascha Haeberling910c1a92014-05-13 13:36:44 -07001477 @Override
Kevin Gabayan05ee74d2014-04-08 16:25:23 -07001478 public void run() {
1479 HashMap memoryData = mMemoryManager.queryMemory();
1480 UsageStatistics.instance().reportMemoryConsumed(memoryData,
1481 MemoryQuery.REPORT_LABEL_LAUNCH);
1482 }
1483 });
Kevin Gabayanfb333362014-06-02 14:48:20 -07001484 mMotionManager = getServices().getMotionManager();
Michael Kolb8872c232013-01-29 10:33:22 -08001485 }
1486
Sascha Haeberling2d11fcf2014-03-13 09:04:32 -07001487 /**
Erin Dahlgren4e0a4642014-03-31 13:54:30 -07001488 * Get the current mode index from the Intent or from persistent
1489 * settings.
1490 */
1491 public int getModeIndex() {
1492 int modeIndex = -1;
1493 int photoIndex = getResources().getInteger(R.integer.camera_mode_photo);
1494 int videoIndex = getResources().getInteger(R.integer.camera_mode_video);
1495 int gcamIndex = getResources().getInteger(R.integer.camera_mode_gcam);
1496 if (MediaStore.INTENT_ACTION_VIDEO_CAMERA.equals(getIntent().getAction())
1497 || MediaStore.ACTION_VIDEO_CAPTURE.equals(getIntent().getAction())) {
1498 modeIndex = videoIndex;
Doris Liue903d532014-05-06 11:11:26 -07001499 } else if (MediaStore.ACTION_IMAGE_CAPTURE.equals(getIntent().getAction())) {
1500 // Capture intent.
Erin Dahlgren4e0a4642014-03-31 13:54:30 -07001501 modeIndex = photoIndex;
Doris Liue903d532014-05-06 11:11:26 -07001502 } else if (MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA.equals(getIntent().getAction())
1503 ||MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE.equals(getIntent()
Erin Dahlgren4e0a4642014-03-31 13:54:30 -07001504 .getAction())
1505 || MediaStore.ACTION_IMAGE_CAPTURE_SECURE.equals(getIntent().getAction())) {
Erin Dahlgren6190c362014-06-13 14:12:08 -07001506 modeIndex = mSettingsManager.getInteger(SettingsManager.SCOPE_GLOBAL,
1507 Keys.KEY_CAMERA_MODULE_LAST_USED);
Doris Liudb8f9752014-05-12 15:25:13 -07001508
1509 // For upgraders who have not seen the aspect ratio selection screen,
1510 // we need to drop them back in the photo module and have them select
1511 // aspect ratio.
1512 // TODO: Move this to SettingsManager as an upgrade procedure.
Erin Dahlgren6190c362014-06-13 14:12:08 -07001513 if (!mSettingsManager.getBoolean(SettingsManager.SCOPE_GLOBAL,
1514 Keys.KEY_USER_SELECTED_ASPECT_RATIO)) {
Doris Liudb8f9752014-05-12 15:25:13 -07001515 modeIndex = photoIndex;
1516 }
Erin Dahlgren4e0a4642014-03-31 13:54:30 -07001517 } else {
1518 // If the activity has not been started using an explicit intent,
1519 // read the module index from the last time the user changed modes
Erin Dahlgren6190c362014-06-13 14:12:08 -07001520 modeIndex = mSettingsManager.getInteger(SettingsManager.SCOPE_GLOBAL,
1521 Keys.KEY_STARTUP_MODULE_INDEX);
Erin Dahlgren4e0a4642014-03-31 13:54:30 -07001522 if ((modeIndex == gcamIndex &&
Sascha Haeberling4c1bffe2014-08-21 10:01:00 -07001523 !GcamHelper.hasGcamAsSeparateModule()) || modeIndex < 0) {
Erin Dahlgren4e0a4642014-03-31 13:54:30 -07001524 modeIndex = photoIndex;
1525 }
1526 }
1527 return modeIndex;
1528 }
1529
1530 /**
Sascha Haeberling2d11fcf2014-03-13 09:04:32 -07001531 * Call this whenever the mode drawer or filmstrip change the visibility
1532 * state.
1533 */
1534 private void updatePreviewVisibility() {
1535 if (mCurrentModule == null) {
1536 return;
1537 }
Sam Judd1b125322014-03-21 16:53:27 -07001538
1539 int visibility = getPreviewVisibility();
Doris Liudfb5a6f2014-04-28 22:36:08 -07001540 mCameraAppUI.onPreviewVisiblityChanged(visibility);
Sam Judd1b125322014-03-21 16:53:27 -07001541 updatePreviewRendering(visibility);
Sascha Haeberling2d11fcf2014-03-13 09:04:32 -07001542 mCurrentModule.onPreviewVisibilityChanged(visibility);
1543 }
1544
Sam Judd1b125322014-03-21 16:53:27 -07001545 private void updatePreviewRendering(int visibility) {
1546 if (visibility == ModuleController.VISIBILITY_HIDDEN) {
1547 mCameraAppUI.pausePreviewRendering();
1548 } else {
1549 mCameraAppUI.resumePreviewRendering();
1550 }
1551 }
1552
1553 private int getPreviewVisibility() {
1554 if (mFilmstripCoversPreview) {
1555 return ModuleController.VISIBILITY_HIDDEN;
1556 } else if (mModeListVisible){
1557 return ModuleController.VISIBILITY_COVERED;
1558 } else {
1559 return ModuleController.VISIBILITY_VISIBLE;
1560 }
1561 }
1562
Doris Liu6432cd62013-06-13 17:20:31 -07001563 private void setRotationAnimation() {
Michael Kolb08650182013-02-25 19:43:56 -08001564 int rotationAnimation = WindowManager.LayoutParams.ROTATION_ANIMATION_ROTATE;
Doris Liu6432cd62013-06-13 17:20:31 -07001565 rotationAnimation = WindowManager.LayoutParams.ROTATION_ANIMATION_CROSSFADE;
Michael Kolb08650182013-02-25 19:43:56 -08001566 Window win = getWindow();
1567 WindowManager.LayoutParams winParams = win.getAttributes();
1568 winParams.rotationAnimation = rotationAnimation;
1569 win.setAttributes(winParams);
1570 }
1571
Michael Kolb8872c232013-01-29 10:33:22 -08001572 @Override
Michael Kolb8872c232013-01-29 10:33:22 -08001573 public void onUserInteraction() {
1574 super.onUserInteraction();
Angus Kong13e87c42013-11-25 10:02:47 -08001575 if (!isFinishing()) {
1576 keepScreenOnForAWhile();
1577 }
Michael Kolb8872c232013-01-29 10:33:22 -08001578 }
1579
1580 @Override
Doris Liu742cd5b2013-09-12 16:17:43 -07001581 public boolean dispatchTouchEvent(MotionEvent ev) {
1582 boolean result = super.dispatchTouchEvent(ev);
1583 if (ev.getActionMasked() == MotionEvent.ACTION_DOWN) {
1584 // Real deletion is postponed until the next user interaction after
Sascha Haeberling846d3ab2014-02-04 12:48:55 +01001585 // the gesture that triggers deletion. Until real deletion is
1586 // performed, users can click the undo button to bring back the
1587 // image that they chose to delete.
Doris Liu742cd5b2013-09-12 16:17:43 -07001588 if (mPendingDeletion && !mIsUndoingDeletion) {
Angus Kong20fad242013-11-11 18:23:46 -08001589 performDeletion();
Doris Liu742cd5b2013-09-12 16:17:43 -07001590 }
1591 }
1592 return result;
1593 }
1594
1595 @Override
Doris Liu6432cd62013-06-13 17:20:31 -07001596 public void onPause() {
Erin Dahlgren5f38da82014-04-01 11:48:40 -07001597 CameraPerformanceTracker.onEvent(CameraPerformanceTracker.ACTIVITY_PAUSE);
1598
Erin Dahlgren4e0a4642014-03-31 13:54:30 -07001599 /*
1600 * Save the last module index after all secure camera and icon launches,
1601 * not just on mode switches.
1602 *
1603 * Right now we exclude capture intents from this logic, because we also
1604 * ignore the cross-Activity recovery logic in onStart for capture intents.
1605 */
1606 if (!isCaptureIntent()) {
Erin Dahlgren6190c362014-06-13 14:12:08 -07001607 mSettingsManager.set(SettingsManager.SCOPE_GLOBAL,
1608 Keys.KEY_STARTUP_MODULE_INDEX,
Erin Dahlgren4e0a4642014-03-31 13:54:30 -07001609 mCurrentModeIndex);
1610 }
1611
Erin Dahlgrenc120b0f2013-11-19 10:53:49 -08001612 mPaused = true;
Angus Kong50521172014-01-17 17:23:59 -08001613 mPeekAnimationHandler = null;
1614 mPeekAnimationThread.quitSafely();
1615 mPeekAnimationThread = null;
Erin Dahlgrenc120b0f2013-11-19 10:53:49 -08001616
Doris Liuf2c14332013-09-26 11:24:37 -07001617 // Delete photos that are pending deletion
1618 performDeletion();
Angus Kongc4e66562013-11-22 23:03:21 -08001619 mCurrentModule.pause();
Angus Kong9f1db522013-11-09 16:25:59 -08001620 mOrientationManager.pause();
Angus Kong20fad242013-11-11 18:23:46 -08001621 // Close the camera and wait for the operation done.
Angus Kong0b9eb5b2014-04-30 15:03:33 -07001622 mCameraController.closeCamera(true);
Alan Newberger04bd11c2014-01-28 18:09:30 -08001623 mPanoramaViewHelper.onPause();
Doris Liu2b86d872013-09-26 15:23:41 -07001624
Sam Juddaeed91f2014-03-13 11:40:10 -07001625 mLocalImagesObserver.setForegroundChangeListener(null);
Doris Liu2b86d872013-09-26 15:23:41 -07001626 mLocalImagesObserver.setActivityPaused(true);
1627 mLocalVideosObserver.setActivityPaused(true);
Sam Juddde3e9ab2014-03-17 13:07:22 -07001628 mPreloader.cancelAllLoads();
Angus Kong13e87c42013-11-25 10:02:47 -08001629 resetScreenOn();
Andy Huibersebd95372014-05-12 14:44:13 -07001630
Kevin Gabayanfb333362014-06-02 14:48:20 -07001631 mMotionManager.stop();
1632
Andy Huibersebd95372014-05-12 14:44:13 -07001633 UsageStatistics.instance().backgrounded();
1634
Angus Kongc4e66562013-11-22 23:03:21 -08001635 super.onPause();
Doris Liu6432cd62013-06-13 17:20:31 -07001636 }
1637
1638 @Override
1639 public void onResume() {
Doris Liu7cbecee2014-01-30 12:29:27 -08001640 CameraPerformanceTracker.onEvent(CameraPerformanceTracker.ACTIVITY_RESUME);
Andy Huiberseaaf2932014-04-28 13:18:31 -07001641 Log.v(TAG, "Build info: " + Build.DISPLAY);
Erin Dahlgrenc120b0f2013-11-19 10:53:49 -08001642
Erin Dahlgren5f38da82014-04-01 11:48:40 -07001643 mPaused = false;
Spike Spraguee6374b72014-04-25 17:24:32 -07001644 updateStorageSpaceAndHint(null);
Erin Dahlgren5f38da82014-04-01 11:48:40 -07001645
Angus Kong53ae0412013-12-01 23:21:49 -08001646 mLastLayoutOrientation = getResources().getConfiguration().orientation;
1647
Angus Kongce2b9492013-09-05 17:49:06 -07001648 // TODO: Handle this in OrientationManager.
Sascha Haeberlinga5a08d72013-09-11 20:30:52 -07001649 // Auto-rotate off
Doris Liu6432cd62013-06-13 17:20:31 -07001650 if (Settings.System.getInt(getContentResolver(),
Sascha Haeberlinga5a08d72013-09-11 20:30:52 -07001651 Settings.System.ACCELEROMETER_ROTATION, 0) == 0) {
Doris Liu6432cd62013-06-13 17:20:31 -07001652 setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
1653 mAutoRotateScreen = false;
1654 } else {
1655 setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR);
1656 mAutoRotateScreen = true;
1657 }
Seth Raphaelcbd82672013-11-05 10:12:36 -08001658
Andy Huibers9a9a1082014-07-31 11:10:24 -07001659 // Foreground event logging. ACTION_STILL_IMAGE_CAMERA and
1660 // INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE are double logged due to
1661 // lockscreen onResume->onPause->onResume sequence.
Andy Huibers0b3f9d52014-06-30 12:47:37 -07001662 int source;
Andy Huibers10c58162014-03-29 14:06:54 -07001663 String action = getIntent().getAction();
Alan Newbergerea7db652014-08-06 14:05:31 -07001664 if (action == null) {
1665 source = ForegroundSource.UNKNOWN_SOURCE;
1666 } else {
1667 switch (action) {
1668 case MediaStore.ACTION_IMAGE_CAPTURE:
1669 source = ForegroundSource.ACTION_IMAGE_CAPTURE;
1670 break;
1671 case MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA:
1672 // was UNKNOWN_SOURCE in Fishlake.
1673 source = ForegroundSource.ACTION_STILL_IMAGE_CAMERA;
1674 break;
1675 case MediaStore.INTENT_ACTION_VIDEO_CAMERA:
1676 // was UNKNOWN_SOURCE in Fishlake.
1677 source = ForegroundSource.ACTION_VIDEO_CAMERA;
1678 break;
1679 case MediaStore.ACTION_VIDEO_CAPTURE:
1680 source = ForegroundSource.ACTION_VIDEO_CAPTURE;
1681 break;
1682 case MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE:
1683 // was ACTION_IMAGE_CAPTURE_SECURE in Fishlake.
1684 source = ForegroundSource.ACTION_STILL_IMAGE_CAMERA_SECURE;
1685 break;
1686 case MediaStore.ACTION_IMAGE_CAPTURE_SECURE:
1687 source = ForegroundSource.ACTION_IMAGE_CAPTURE_SECURE;
1688 break;
1689 case Intent.ACTION_MAIN:
1690 source = ForegroundSource.ACTION_MAIN;
1691 break;
1692 default:
1693 source = ForegroundSource.UNKNOWN_SOURCE;
1694 break;
1695 }
Erin Dahlgrenf6edd532014-01-31 11:13:33 -08001696 }
Andy Huibers0b3f9d52014-06-30 12:47:37 -07001697 UsageStatistics.instance().foregrounded(source, currentUserInterfaceMode());
Seth Raphaelcbd82672013-11-05 10:12:36 -08001698
Spike Sprague4f93e192014-08-19 18:53:41 -07001699 mGalleryIntent = IntentHelper.getGalleryIntent(mAppContext);
1700 boolean isOsVersionL = mAppContext.getResources().getBoolean(R.bool.is_os_version_l);
1701 if (isOsVersionL) {
1702 // hide the up affordance for L devices, it's not very Materially
1703 mActionBar.setDisplayShowHomeEnabled(false);
Angus Kong6c0c7f12014-01-15 14:40:27 -08001704 }
Spike Sprague4f93e192014-08-19 18:53:41 -07001705
Angus Kong9f1db522013-11-09 16:25:59 -08001706 mOrientationManager.resume();
Doris Liu6432cd62013-06-13 17:20:31 -07001707 super.onResume();
Angus Kong50521172014-01-17 17:23:59 -08001708 mPeekAnimationThread = new HandlerThread("Peek animation");
1709 mPeekAnimationThread.start();
1710 mPeekAnimationHandler = new PeekAnimationHandler(mPeekAnimationThread.getLooper());
Erin Dahlgren1ca516f2014-03-28 12:44:04 -07001711
1712 mCurrentModule.hardResetSettings(mSettingsManager);
Angus Kongc4e66562013-11-22 23:03:21 -08001713 mCurrentModule.resume();
Andy Huibers10c58162014-03-29 14:06:54 -07001714 UsageStatistics.instance().changeScreen(currentUserInterfaceMode(),
1715 NavigationChange.InteractionCause.BUTTON);
Angus Kong6798c342013-07-16 15:14:58 -07001716 setSwipingEnabled(true);
Sascha Haeberlingb7639c62013-09-09 14:42:43 -07001717
Erin Dahlgren4e0a4642014-03-31 13:54:30 -07001718 if (!mResetToPreviewOnResume) {
Sascha Haeberling846d3ab2014-02-04 12:48:55 +01001719 LocalData data = mDataAdapter.getLocalData(mFilmstripController.getCurrentId());
Angus Kong2520b502014-01-10 17:45:27 -08001720 if (data != null) {
Angus Kong571a8c32014-03-13 12:53:03 -07001721 mDataAdapter.refresh(data.getUri());
Angus Kong2520b502014-01-10 17:45:27 -08001722 }
Sascha Haeberlingb7639c62013-09-09 14:42:43 -07001723 }
Angus Konge4002f32013-12-13 22:24:11 -08001724 // The share button might be disabled to avoid double tapping.
1725 mCameraAppUI.getFilmstripBottomControls().setShareEnabled(true);
Sascha Haeberlingb7639c62013-09-09 14:42:43 -07001726 // Default is showing the preview, unless disabled by explicitly
1727 // starting an activity we want to return from to the filmstrip rather
1728 // than the preview.
1729 mResetToPreviewOnResume = true;
ztenghui064d6002013-09-05 15:47:58 -07001730
Doris Liu2b86d872013-09-26 15:23:41 -07001731 if (mLocalVideosObserver.isMediaDataChangedDuringPause()
1732 || mLocalImagesObserver.isMediaDataChangedDuringPause()) {
Angus Kong2d5c7472013-10-12 23:48:46 -07001733 if (!mSecureCamera) {
1734 // If it's secure camera, requestLoad() should not be called
1735 // as it will load all the data.
Angus Kongb2510252013-12-10 22:58:15 -08001736 if (!mFilmstripVisible) {
Sascha Haeberlingadde93f2014-03-31 16:58:11 -07001737 mDataAdapter.requestLoad(new Callback<Void>() {
1738 @Override
1739 public void onCallback(Void result) {
1740 fillTemporarySessions();
1741 }
1742 });
Sam Juddaeed91f2014-03-13 11:40:10 -07001743 } else {
1744 mDataAdapter.requestLoadNewPhotos();
Angus Kongb2510252013-12-10 22:58:15 -08001745 }
Angus Kong2d5c7472013-10-12 23:48:46 -07001746 }
ztenghui064d6002013-09-05 15:47:58 -07001747 }
Doris Liu2b86d872013-09-26 15:23:41 -07001748 mLocalImagesObserver.setActivityPaused(false);
1749 mLocalVideosObserver.setActivityPaused(false);
Sam Judd6383d972014-03-18 16:00:32 -07001750 if (!mSecureCamera) {
1751 mLocalImagesObserver.setForegroundChangeListener(
1752 new LocalMediaObserver.ChangeListener() {
1753 @Override
1754 public void onChange() {
1755 mDataAdapter.requestLoadNewPhotos();
1756 }
1757 });
1758 }
Doris Liu70576b62013-11-14 20:30:33 -08001759
Angus Kong13e87c42013-11-25 10:02:47 -08001760 keepScreenOnForAWhile();
Sascha Haeberling20639e72014-01-07 13:31:19 -08001761
Sascha Haeberling39675162014-04-02 18:16:42 -07001762 // Lights-out mode at all times.
Sascha Haeberling099b49b2014-04-08 07:08:46 -07001763 final View rootView = findViewById(R.id.activity_root_view);
1764 mLightsOutRunnable.run();
1765 getWindow().getDecorView().setOnSystemUiVisibilityChangeListener(
1766 new OnSystemUiVisibilityChangeListener() {
1767 @Override
1768 public void onSystemUiVisibilityChange(int visibility) {
1769 mMainHandler.removeCallbacks(mLightsOutRunnable);
1770 mMainHandler.postDelayed(mLightsOutRunnable, LIGHTS_OUT_DELAY_MS);
1771 }
1772 });
Sascha Haeberling39675162014-04-02 18:16:42 -07001773
Alan Newberger04bd11c2014-01-28 18:09:30 -08001774 mPanoramaViewHelper.onResume();
Sascha Haeberling7190c6a2014-02-21 10:11:31 -08001775 ReleaseDialogHelper.showReleaseInfoDialogOnStart(this, mSettingsManager);
Sascha Haeberling91c25e32014-02-26 14:10:48 -08001776 syncLocationManagerSetting();
Sam Judd1b125322014-03-21 16:53:27 -07001777
1778 final int previewVisibility = getPreviewVisibility();
1779 updatePreviewRendering(previewVisibility);
Kevin Gabayanfb333362014-06-02 14:48:20 -07001780
1781 mMotionManager.start();
Angus Kong6798c342013-07-16 15:14:58 -07001782 }
1783
Sascha Haeberlingadde93f2014-03-31 16:58:11 -07001784 private void fillTemporarySessions() {
1785 if (mSecureCamera) {
1786 return;
1787 }
1788 // There might be sessions still in flight (processed by our service).
1789 // Make sure they're added to the filmstrip.
1790 getServices().getCaptureSessionManager().fillTemporarySession(mSessionListener);
1791 }
1792
Angus Kong6798c342013-07-16 15:14:58 -07001793 @Override
1794 public void onStart() {
1795 super.onStart();
Sascha Haeberlingca82f502014-07-15 08:54:40 -07001796 mIsActivityRunning = true;
Sascha Haeberlingf1f51862013-07-31 11:28:21 -07001797 mPanoramaViewHelper.onStart();
Erin Dahlgren4e0a4642014-03-31 13:54:30 -07001798
1799 /*
1800 * If we're starting after launching a different Activity (lockscreen),
1801 * we need to use the last mode used in the other Activity, and
1802 * not the old one from this Activity.
1803 *
1804 * This needs to happen before CameraAppUI.resume() in order to set the
1805 * mode cover icon to the actual last mode used.
1806 *
1807 * Right now we exclude capture intents from this logic.
1808 */
1809 int modeIndex = getModeIndex();
1810 if (!isCaptureIntent() && mCurrentModeIndex != modeIndex) {
1811 onModeSelected(modeIndex);
1812 }
1813
Seth Raphael7dcf8b12014-03-11 16:44:25 -07001814 if (mResetToPreviewOnResume) {
1815 mCameraAppUI.resume();
1816 mResetToPreviewOnResume = false;
1817 }
Sascha Haeberlingf1f51862013-07-31 11:28:21 -07001818 }
1819
1820 @Override
1821 protected void onStop() {
Sascha Haeberlingca82f502014-07-15 08:54:40 -07001822 mIsActivityRunning = false;
Sascha Haeberlingf1f51862013-07-31 11:28:21 -07001823 mPanoramaViewHelper.onStop();
Angus Kong0e57fc12013-11-18 13:21:07 -08001824
Kevin Gabayanffbc43c2013-12-09 11:41:50 -08001825 mLocationManager.disconnect();
Angus Kong0e57fc12013-11-18 13:21:07 -08001826 super.onStop();
Doris Liu6432cd62013-06-13 17:20:31 -07001827 }
1828
1829 @Override
1830 public void onDestroy() {
Sascha Haeberlinga5a08d72013-09-11 20:30:52 -07001831 if (mSecureCamera) {
1832 unregisterReceiver(mScreenOffReceiver);
1833 }
Spike Spragueba97d192014-08-19 15:33:45 -07001834 mActionBar.removeOnMenuVisibilityListener(mOnMenuVisibilityListener);
Erin Dahlgren1648c362014-01-06 15:06:04 -08001835 mSettingsManager.removeAllListeners();
Sascha Haeberling846d3ab2014-02-04 12:48:55 +01001836 mCameraController.removeCallbackReceiver();
ztenghui064d6002013-09-05 15:47:58 -07001837 getContentResolver().unregisterContentObserver(mLocalImagesObserver);
1838 getContentResolver().unregisterContentObserver(mLocalVideosObserver);
Sascha Haeberling846d3ab2014-02-04 12:48:55 +01001839 getServices().getCaptureSessionManager().removeSessionListener(mSessionListener);
1840 mCameraAppUI.onDestroy();
Doris Liu3cea8cc2014-03-25 17:59:05 -07001841 mModeListView.setVisibilityChangedListener(null);
Sascha Haeberling846d3ab2014-02-04 12:48:55 +01001842 mCameraController = null;
1843 mSettingsManager = null;
Sascha Haeberling846d3ab2014-02-04 12:48:55 +01001844 mCameraAppUI = null;
1845 mOrientationManager = null;
1846 mButtonManager = null;
Sol Boucher44ce4b22014-08-04 23:41:38 -07001847 CameraAgentFactory.recycle(CameraAgentFactory.CameraApi.API_1);
1848 CameraAgentFactory.recycle(CameraAgentFactory.CameraApi.AUTO);
Sascha Haeberling2d4be252014-08-27 17:56:08 -07001849 mSoundPlayer.release();
Doris Liu6432cd62013-06-13 17:20:31 -07001850 super.onDestroy();
1851 }
1852
1853 @Override
1854 public void onConfigurationChanged(Configuration config) {
1855 super.onConfigurationChanged(config);
Angus Kong166e36f2013-12-03 08:54:42 -08001856 Log.v(TAG, "onConfigurationChanged");
Angus Kong2f0e4a32013-12-03 10:02:35 -08001857 if (config.orientation == Configuration.ORIENTATION_UNDEFINED) {
1858 return;
1859 }
1860
Angus Kong53ae0412013-12-01 23:21:49 -08001861 if (mLastLayoutOrientation != config.orientation) {
1862 mLastLayoutOrientation = config.orientation;
Angus Kong2f0e4a32013-12-03 10:02:35 -08001863 mCurrentModule.onLayoutOrientationChanged(
1864 mLastLayoutOrientation == Configuration.ORIENTATION_LANDSCAPE);
Angus Kong53ae0412013-12-01 23:21:49 -08001865 }
Doris Liu6432cd62013-06-13 17:20:31 -07001866 }
1867
1868 @Override
1869 public boolean onKeyDown(int keyCode, KeyEvent event) {
Angus Kong8dcccb12014-01-02 16:00:49 -08001870 if (!mFilmstripVisible) {
Doris Liudba16ae2013-10-03 15:31:40 -07001871 if (mCurrentModule.onKeyDown(keyCode, event)) {
Sascha Haeberlinga5a08d72013-09-11 20:30:52 -07001872 return true;
1873 }
Doris Liudba16ae2013-10-03 15:31:40 -07001874 // Prevent software keyboard or voice search from showing up.
1875 if (keyCode == KeyEvent.KEYCODE_SEARCH
1876 || keyCode == KeyEvent.KEYCODE_MENU) {
1877 if (event.isLongPress()) {
1878 return true;
1879 }
1880 }
Doris Liu6432cd62013-06-13 17:20:31 -07001881 }
Doris Liu6432cd62013-06-13 17:20:31 -07001882
1883 return super.onKeyDown(keyCode, event);
1884 }
1885
1886 @Override
1887 public boolean onKeyUp(int keyCode, KeyEvent event) {
Erin Dahlgren15691af2014-03-14 14:10:57 -07001888 if (!mFilmstripVisible) {
1889 // If a module is in the middle of capture, it should
1890 // consume the key event.
1891 if (mCurrentModule.onKeyUp(keyCode, event)) {
1892 return true;
Alan Newberger623dd0c2014-03-24 15:55:23 -07001893 } else if (keyCode == KeyEvent.KEYCODE_MENU
1894 || keyCode == KeyEvent.KEYCODE_DPAD_LEFT) {
Erin Dahlgren15691af2014-03-14 14:10:57 -07001895 // Let the mode list view consume the event.
Sascha Haeberling256427b2014-05-15 14:45:02 -07001896 mCameraAppUI.openModeList();
Erin Dahlgren15691af2014-03-14 14:10:57 -07001897 return true;
Alan Newberger623dd0c2014-03-24 15:55:23 -07001898 } else if (keyCode == KeyEvent.KEYCODE_DPAD_RIGHT) {
1899 mCameraAppUI.showFilmstrip();
1900 return true;
Erin Dahlgren15691af2014-03-14 14:10:57 -07001901 }
Alan Newberger8099a372014-03-24 17:17:38 -07001902 } else {
1903 if (keyCode == KeyEvent.KEYCODE_DPAD_RIGHT) {
1904 mFilmstripController.goToNextItem();
1905 return true;
1906 } else if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT) {
1907 boolean wentToPrevious = mFilmstripController.goToPreviousItem();
1908 if (!wentToPrevious) {
1909 // at beginning of filmstrip, hide and go back to preview
1910 mCameraAppUI.hideFilmstrip();
1911 }
1912 return true;
1913 }
Sascha Haeberlinga5a08d72013-09-11 20:30:52 -07001914 }
Doris Liu6432cd62013-06-13 17:20:31 -07001915 return super.onKeyUp(keyCode, event);
1916 }
1917
Alan Newberger5f6b50d2013-08-30 15:19:48 -07001918 @Override
1919 public void onBackPressed() {
Angus Kong166e36f2013-12-03 08:54:42 -08001920 if (!mCameraAppUI.onBackPressed()) {
1921 if (!mCurrentModule.onBackPressed()) {
1922 super.onBackPressed();
1923 }
Alan Newberger5f6b50d2013-08-30 15:19:48 -07001924 }
1925 }
1926
Sascha Haeberlinga7cbfc02014-02-14 11:06:03 +01001927 @Override
Doris Liu6432cd62013-06-13 17:20:31 -07001928 public boolean isAutoRotateScreen() {
Sascha Haeberlinga7cbfc02014-02-14 11:06:03 +01001929 // TODO: Move to OrientationManager.
Doris Liu6432cd62013-06-13 17:20:31 -07001930 return mAutoRotateScreen;
1931 }
1932
Sascha Haeberlingd114a772014-02-28 21:27:27 -08001933 @Override
1934 public boolean onCreateOptionsMenu(Menu menu) {
1935 MenuInflater inflater = getMenuInflater();
1936 inflater.inflate(R.menu.filmstrip_menu, menu);
1937 mActionBarMenu = menu;
Spike Sprague4f93e192014-08-19 18:53:41 -07001938
1939 // add a button for launching the gallery
1940 if (mGalleryIntent != null) {
1941 CharSequence appName = IntentHelper.getGalleryAppName(mAppContext, mGalleryIntent);
1942 if (appName != null) {
1943 MenuItem menuItem = menu.add(appName);
1944 menuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
1945 menuItem.setIntent(mGalleryIntent);
1946
1947 Drawable galleryLogo = IntentHelper.getGalleryIcon(mAppContext, mGalleryIntent);
1948 if (galleryLogo != null) {
1949 menuItem.setIcon(galleryLogo);
1950 }
1951 }
1952 }
1953
Sascha Haeberlingd114a772014-02-28 21:27:27 -08001954 return super.onCreateOptionsMenu(menu);
1955 }
1956
Angus Kong2dcc0a92013-09-25 13:00:08 -07001957 protected long getStorageSpaceBytes() {
Erin Dahlgrenc4fbb3d2014-04-01 15:11:34 -07001958 synchronized (mStorageSpaceLock) {
1959 return mStorageSpaceBytes;
1960 }
Doris Liu6432cd62013-06-13 17:20:31 -07001961 }
1962
Spike Spraguee6374b72014-04-25 17:24:32 -07001963 protected interface OnStorageUpdateDoneListener {
1964 public void onStorageUpdateDone(long bytes);
1965 }
1966
1967 protected void updateStorageSpaceAndHint(final OnStorageUpdateDoneListener callback) {
Erin Dahlgrenc4fbb3d2014-04-01 15:11:34 -07001968 /*
1969 * We execute disk operations on a background thread in order to
1970 * free up the UI thread. Synchronizing on the lock below ensures
1971 * that when getStorageSpaceBytes is called, the main thread waits
1972 * until this method has completed.
Spike Spraguee6374b72014-04-25 17:24:32 -07001973 *
1974 * However, .execute() does not ensure this execution block will be
1975 * run right away (.execute() schedules this AsyncTask for sometime
1976 * in the future. executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR)
1977 * tries to execute the task in parellel with other AsyncTasks, but
1978 * there's still no guarantee).
1979 * e.g. don't call this then immediately call getStorageSpaceBytes().
1980 * Instead, pass in an OnStorageUpdateDoneListener.
Erin Dahlgrenc4fbb3d2014-04-01 15:11:34 -07001981 */
Spike Spraguee6374b72014-04-25 17:24:32 -07001982 (new AsyncTask<Void, Void, Long>() {
Erin Dahlgrenc4fbb3d2014-04-01 15:11:34 -07001983 @Override
Spike Spraguee6374b72014-04-25 17:24:32 -07001984 protected Long doInBackground(Void ... arg) {
Erin Dahlgrenc4fbb3d2014-04-01 15:11:34 -07001985 synchronized (mStorageSpaceLock) {
1986 mStorageSpaceBytes = Storage.getAvailableSpace();
Spike Spraguee6374b72014-04-25 17:24:32 -07001987 return mStorageSpaceBytes;
Erin Dahlgrenc4fbb3d2014-04-01 15:11:34 -07001988 }
Erin Dahlgrenc4fbb3d2014-04-01 15:11:34 -07001989 }
1990
1991 @Override
Spike Spraguee6374b72014-04-25 17:24:32 -07001992 protected void onPostExecute(Long bytes) {
1993 updateStorageHint(bytes);
Alan Newberger26b224d2014-08-26 18:18:48 -07001994 // This callback returns after I/O to check disk, so we could be
1995 // pausing and shutting down. If so, don't bother invoking.
1996 if (callback != null && !mPaused) {
Spike Spraguee6374b72014-04-25 17:24:32 -07001997 callback.onStorageUpdateDone(bytes);
Alan Newberger26b224d2014-08-26 18:18:48 -07001998 } else {
1999 Log.v(TAG, "ignoring storage callback after activity pause");
Spike Spraguee6374b72014-04-25 17:24:32 -07002000 }
Erin Dahlgrenc4fbb3d2014-04-01 15:11:34 -07002001 }
Spike Spraguee6374b72014-04-25 17:24:32 -07002002 }).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
Doris Liu6432cd62013-06-13 17:20:31 -07002003 }
2004
2005 protected void updateStorageHint(long storageSpace) {
Sascha Haeberlingca82f502014-07-15 08:54:40 -07002006 if (!mIsActivityRunning) {
2007 return;
2008 }
2009
Doris Liu6432cd62013-06-13 17:20:31 -07002010 String message = null;
2011 if (storageSpace == Storage.UNAVAILABLE) {
2012 message = getString(R.string.no_storage);
2013 } else if (storageSpace == Storage.PREPARING) {
2014 message = getString(R.string.preparing_sd);
2015 } else if (storageSpace == Storage.UNKNOWN_SIZE) {
2016 message = getString(R.string.access_sd_fail);
Angus Kong2dcc0a92013-09-25 13:00:08 -07002017 } else if (storageSpace <= Storage.LOW_STORAGE_THRESHOLD_BYTES) {
Doris Liu6432cd62013-06-13 17:20:31 -07002018 message = getString(R.string.spaceIsLow_content);
2019 }
2020
2021 if (message != null) {
Alan Newbergere95aefe2014-04-30 15:36:50 -07002022 Log.w(TAG, "Storage warning: " + message);
Doris Liu6432cd62013-06-13 17:20:31 -07002023 if (mStorageHint == null) {
Alan Newbergere95aefe2014-04-30 15:36:50 -07002024 mStorageHint = OnScreenHint.makeText(CameraActivity.this, message);
Doris Liu6432cd62013-06-13 17:20:31 -07002025 } else {
2026 mStorageHint.setText(message);
2027 }
2028 mStorageHint.show();
Andy Huibersebd95372014-05-12 14:44:13 -07002029 UsageStatistics.instance().storageWarning(storageSpace);
Doris Liu6432cd62013-06-13 17:20:31 -07002030 } else if (mStorageHint != null) {
2031 mStorageHint.cancel();
2032 mStorageHint = null;
Andy Huibersebd95372014-05-12 14:44:13 -07002033 }
Doris Liu6432cd62013-06-13 17:20:31 -07002034 }
2035
2036 protected void setResultEx(int resultCode) {
2037 mResultCodeForTesting = resultCode;
2038 setResult(resultCode);
2039 }
2040
2041 protected void setResultEx(int resultCode, Intent data) {
2042 mResultCodeForTesting = resultCode;
2043 mResultDataForTesting = data;
2044 setResult(resultCode, data);
2045 }
2046
2047 public int getResultCode() {
2048 return mResultCodeForTesting;
2049 }
2050
2051 public Intent getResultData() {
2052 return mResultDataForTesting;
2053 }
2054
2055 public boolean isSecureCamera() {
2056 return mSecureCamera;
Michael Kolb8872c232013-01-29 10:33:22 -08002057 }
2058
2059 @Override
Erin Dahlgrenc120b0f2013-11-19 10:53:49 -08002060 public boolean isPaused() {
2061 return mPaused;
2062 }
2063
2064 @Override
Erin Dahlgren1ba90e32014-03-03 12:05:57 -08002065 public int getPreferredChildModeIndex(int modeIndex) {
2066 if (modeIndex == getResources().getInteger(R.integer.camera_mode_photo)) {
Erin Dahlgren6190c362014-06-13 14:12:08 -07002067 boolean hdrPlusOn = Keys.isHdrPlusOn(mSettingsManager);
Sascha Haeberling4c1bffe2014-08-21 10:01:00 -07002068 if (hdrPlusOn && GcamHelper.hasGcamAsSeparateModule()) {
Erin Dahlgren1ba90e32014-03-03 12:05:57 -08002069 modeIndex = getResources().getInteger(R.integer.camera_mode_gcam);
2070 }
2071 }
2072 return modeIndex;
2073 }
2074
2075 @Override
Erin Dahlgrenc120b0f2013-11-19 10:53:49 -08002076 public void onModeSelected(int modeIndex) {
2077 if (mCurrentModeIndex == modeIndex) {
Sascha Haeberlinga5a08d72013-09-11 20:30:52 -07002078 return;
2079 }
Doris Liu6432cd62013-06-13 17:20:31 -07002080
Doris Liu7cbecee2014-01-30 12:29:27 -08002081 CameraPerformanceTracker.onEvent(CameraPerformanceTracker.MODE_SWITCH_START);
Doris Liucf8b6532014-01-15 19:17:38 -08002082 // Record last used camera mode for quick switching
2083 if (modeIndex == getResources().getInteger(R.integer.camera_mode_photo)
Erin Dahlgrena6587a12014-02-03 13:24:55 -08002084 || modeIndex == getResources().getInteger(R.integer.camera_mode_gcam)) {
Erin Dahlgren6190c362014-06-13 14:12:08 -07002085 mSettingsManager.set(SettingsManager.SCOPE_GLOBAL,
2086 Keys.KEY_CAMERA_MODULE_LAST_USED,
2087 modeIndex);
Doris Liucf8b6532014-01-15 19:17:38 -08002088 }
2089
Doris Liu6432cd62013-06-13 17:20:31 -07002090 closeModule(mCurrentModule);
Erin Dahlgrena340f072014-01-06 17:31:23 -08002091
Erin Dahlgren1ba90e32014-03-03 12:05:57 -08002092 // Select the correct module index from the mode switcher index.
2093 modeIndex = getPreferredChildModeIndex(modeIndex);
Erin Dahlgrenc120b0f2013-11-19 10:53:49 -08002094 setModuleFromModeIndex(modeIndex);
Doris Liuf55f3c42013-11-20 00:24:46 -08002095
Erin Dahlgrend8de0772014-02-03 10:12:27 -08002096 mCameraAppUI.resetBottomControls(mCurrentModule, modeIndex);
Erin Dahlgren5d187692014-02-25 19:16:12 -08002097 mCameraAppUI.addShutterListener(mCurrentModule);
Seth Raphael6382c702014-05-20 13:19:16 -07002098 mCameraAppUI.hideLetterboxing();
Sascha Haeberling2654dd92013-08-28 15:28:57 -07002099 openModule(mCurrentModule);
2100 mCurrentModule.onOrientationChanged(mLastRawOrientation);
Sascha Haeberling2654dd92013-08-28 15:28:57 -07002101 // Store the module index so we can use it the next time the Camera
2102 // starts up.
Erin Dahlgren6190c362014-06-13 14:12:08 -07002103 mSettingsManager.set(SettingsManager.SCOPE_GLOBAL,
2104 Keys.KEY_STARTUP_MODULE_INDEX, modeIndex);
Erin Dahlgrenc120b0f2013-11-19 10:53:49 -08002105 }
2106
Sascha Haeberlingde303232014-02-07 02:30:53 +01002107 /**
2108 * Shows the settings dialog.
2109 */
Doris Liu9d264302014-02-11 10:41:40 -08002110 @Override
Doris Liuf55f3c42013-11-20 00:24:46 -08002111 public void onSettingsSelected() {
Andy Huibers10c58162014-03-29 14:06:54 -07002112 UsageStatistics.instance().controlUsed(
2113 eventprotos.ControlEvent.ControlType.OVERALL_SETTINGS);
Sascha Haeberlingde303232014-02-07 02:30:53 +01002114 Intent intent = new Intent(this, CameraSettingsActivity.class);
2115 startActivity(intent);
Sascha Haeberling2654dd92013-08-28 15:28:57 -07002116 }
2117
Doris Liu6809eb82014-05-21 13:16:59 -07002118 @Override
2119 public void freezeScreenUntilPreviewReady() {
2120 mCameraAppUI.freezeScreenUntilPreviewReady();
2121 }
2122
Sascha Haeberling2654dd92013-08-28 15:28:57 -07002123 /**
Sascha Haeberlinga5a08d72013-09-11 20:30:52 -07002124 * Sets the mCurrentModuleIndex, creates a new module instance for the given
2125 * index an sets it as mCurrentModule.
Sascha Haeberling2654dd92013-08-28 15:28:57 -07002126 */
Erin Dahlgrenc120b0f2013-11-19 10:53:49 -08002127 private void setModuleFromModeIndex(int modeIndex) {
2128 ModuleManagerImpl.ModuleAgent agent = mModuleManager.getModuleAgent(modeIndex);
Angus Kong20fad242013-11-11 18:23:46 -08002129 if (agent == null) {
2130 return;
Doris Liu6432cd62013-06-13 17:20:31 -07002131 }
Angus Kong20fad242013-11-11 18:23:46 -08002132 if (!agent.requestAppForCamera()) {
Angus Kong0b9eb5b2014-04-30 15:03:33 -07002133 mCameraController.closeCamera(true);
Angus Kong20fad242013-11-11 18:23:46 -08002134 }
Erin Dahlgrenc120b0f2013-11-19 10:53:49 -08002135 mCurrentModeIndex = agent.getModuleId();
Sascha Haeberling846d3ab2014-02-04 12:48:55 +01002136 mCurrentModule = (CameraModule) agent.createModule(this);
Michael Kolb8872c232013-01-29 10:33:22 -08002137 }
2138
Erin Dahlgrenc120b0f2013-11-19 10:53:49 -08002139 @Override
2140 public SettingsManager getSettingsManager() {
2141 return mSettingsManager;
2142 }
2143
Angus Kongc4e66562013-11-22 23:03:21 -08002144 @Override
2145 public CameraServices getServices() {
2146 return (CameraServices) getApplication();
2147 }
2148
Erin Dahlgrenf63967a2014-01-02 13:57:43 -08002149 public List<String> getSupportedModeNames() {
2150 List<Integer> indices = mModuleManager.getSupportedModeIndexList();
2151 List<String> supported = new ArrayList<String>();
2152
2153 for (Integer modeIndex : indices) {
Sascha Haeberling846d3ab2014-02-04 12:48:55 +01002154 String name = CameraUtil.getCameraModeText(modeIndex, mAppContext);
Erin Dahlgrenf63967a2014-01-02 13:57:43 -08002155 if (name != null && !name.equals("")) {
2156 supported.add(name);
2157 }
2158 }
2159 return supported;
2160 }
2161
Erin Dahlgren18484942014-01-07 11:46:57 -08002162 @Override
Erin Dahlgren18e2ef62013-12-05 14:53:38 -08002163 public ButtonManager getButtonManager() {
Erin Dahlgren8a2933b2013-12-06 12:07:33 -08002164 if (mButtonManager == null) {
2165 mButtonManager = new ButtonManager(this);
2166 }
2167 return mButtonManager;
Erin Dahlgren18e2ef62013-12-05 14:53:38 -08002168 }
2169
Sascha Haeberling2d4be252014-08-27 17:56:08 -07002170 @Override
2171 public SoundPlayer getSoundPlayer() {
2172 return mSoundPlayer;
2173 }
2174
Sascha Haeberling88ef7662013-08-15 17:19:22 -07002175 /**
Sascha Haeberling846d3ab2014-02-04 12:48:55 +01002176 * Creates an AlertDialog appropriate for choosing whether to enable
2177 * location on the first run of the app.
Erin Dahlgren491c6282013-11-25 13:22:07 -08002178 */
2179 public AlertDialog getFirstTimeLocationAlert() {
Sascha Haeberlingf526f2f2014-02-05 22:06:27 +01002180 AlertDialog.Builder builder = new AlertDialog.Builder(this);
Sascha Haeberlingde303232014-02-07 02:30:53 +01002181 builder = SettingsUtil.getFirstTimeLocationAlertBuilder(builder, new Callback<Boolean>() {
2182 @Override
2183 public void onCallback(Boolean locationOn) {
Erin Dahlgren6190c362014-06-13 14:12:08 -07002184 Keys.setLocation(mSettingsManager, locationOn, mLocationManager);
Sascha Haeberlingde303232014-02-07 02:30:53 +01002185 }
2186 });
Erin Dahlgren491c6282013-11-25 13:22:07 -08002187 if (builder != null) {
2188 return builder.create();
2189 } else {
2190 return null;
2191 }
2192 }
2193
2194 /**
Sascha Haeberlinge8959e72014-01-31 15:21:02 +01002195 * Launches an ACTION_EDIT intent for the given local data item. If
2196 * 'withTinyPlanet' is set, this will show a disambig dialog first to let
2197 * the user start either the tiny planet editor or another photo edior.
2198 *
2199 * @param data The data item to edit.
Sascha Haeberling88ef7662013-08-15 17:19:22 -07002200 */
2201 public void launchEditor(LocalData data) {
2202 Intent intent = new Intent(Intent.ACTION_EDIT)
Angus Kong571a8c32014-03-13 12:53:03 -07002203 .setDataAndType(data.getUri(), data.getMimeType())
Sascha Haeberling88ef7662013-08-15 17:19:22 -07002204 .setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
Erin Dahlgren05a04922013-11-07 11:35:10 -08002205 try {
Angus Kong0eaf0162013-12-16 15:53:30 -08002206 launchActivityByIntent(intent);
Erin Dahlgren05a04922013-11-07 11:35:10 -08002207 } catch (ActivityNotFoundException e) {
Sascha Haeberling910c1a92014-05-13 13:36:44 -07002208 final String msgEditWith = getResources().getString(R.string.edit_with);
2209 launchActivityByIntent(Intent.createChooser(intent, msgEditWith));
Erin Dahlgren05a04922013-11-07 11:35:10 -08002210 }
Sascha Haeberling88ef7662013-08-15 17:19:22 -07002211 }
2212
Sascha Haeberlinge8959e72014-01-31 15:21:02 +01002213 @Override
2214 public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
2215 super.onCreateContextMenu(menu, v, menuInfo);
2216
2217 MenuInflater inflater = getMenuInflater();
2218 inflater.inflate(R.menu.filmstrip_context_menu, menu);
2219 }
2220
2221 @Override
2222 public boolean onContextItemSelected(MenuItem item) {
Sascha Haeberling846d3ab2014-02-04 12:48:55 +01002223 switch (item.getItemId()) {
Sascha Haeberlinge8959e72014-01-31 15:21:02 +01002224 case R.id.tiny_planet_editor:
2225 mMyFilmstripBottomControlListener.onTinyPlanet();
2226 return true;
2227 case R.id.photo_editor:
2228 mMyFilmstripBottomControlListener.onEdit();
2229 return true;
2230 }
2231 return false;
2232 }
2233
Sascha Haeberlinga5a08d72013-09-11 20:30:52 -07002234 /**
2235 * Launch the tiny planet editor.
2236 *
Angus Kong20fad242013-11-11 18:23:46 -08002237 * @param data The data must be a 360 degree stereographically mapped
Sascha Haeberling846d3ab2014-02-04 12:48:55 +01002238 * panoramic image. It will not be modified, instead a new item
2239 * with the result will be added to the filmstrip.
Sascha Haeberlinga5a08d72013-09-11 20:30:52 -07002240 */
2241 public void launchTinyPlanetEditor(LocalData data) {
2242 TinyPlanetFragment fragment = new TinyPlanetFragment();
2243 Bundle bundle = new Bundle();
Angus Kong571a8c32014-03-13 12:53:03 -07002244 bundle.putString(TinyPlanetFragment.ARGUMENT_URI, data.getUri().toString());
Sascha Haeberlinga5a08d72013-09-11 20:30:52 -07002245 bundle.putString(TinyPlanetFragment.ARGUMENT_TITLE, data.getTitle());
2246 fragment.setArguments(bundle);
2247 fragment.show(getFragmentManager(), "tiny_planet");
2248 }
2249
Andy Huibers10c58162014-03-29 14:06:54 -07002250 /**
2251 * Returns what UI mode (capture mode or filmstrip) we are in.
2252 * Returned number one of {@link com.google.common.logging.eventprotos.NavigationChange.Mode}
2253 */
2254 private int currentUserInterfaceMode() {
2255 int mode = NavigationChange.Mode.UNKNOWN_MODE;
2256 if (mCurrentModeIndex == getResources().getInteger(R.integer.camera_mode_photo)) {
2257 mode = NavigationChange.Mode.PHOTO_CAPTURE;
2258 }
2259 if (mCurrentModeIndex == getResources().getInteger(R.integer.camera_mode_video)) {
2260 mode = NavigationChange.Mode.VIDEO_CAPTURE;
2261 }
2262 if (mCurrentModeIndex == getResources().getInteger(R.integer.camera_mode_refocus)) {
2263 mode = NavigationChange.Mode.LENS_BLUR;
2264 }
2265 if (mCurrentModeIndex == getResources().getInteger(R.integer.camera_mode_gcam)) {
2266 mode = NavigationChange.Mode.HDR_PLUS;
2267 }
2268 if (mCurrentModeIndex == getResources().getInteger(R.integer.camera_mode_photosphere)) {
2269 mode = NavigationChange.Mode.PHOTO_SPHERE;
2270 }
2271 if (mCurrentModeIndex == getResources().getInteger(R.integer.camera_mode_panorama)) {
2272 mode = NavigationChange.Mode.PANORAMA;
2273 }
2274 if (mFilmstripVisible) {
2275 mode = NavigationChange.Mode.FILMSTRIP;
2276 }
2277 return mode;
2278 }
2279
Erin Dahlgrencb99b3d2014-01-07 17:16:20 -08002280 private void openModule(CameraModule module) {
Angus Kong13e87c42013-11-25 10:02:47 -08002281 module.init(this, isSecureCamera(), isCaptureIntent());
Erin Dahlgren1ca516f2014-03-28 12:44:04 -07002282 module.hardResetSettings(mSettingsManager);
Angus Kongc4e66562013-11-22 23:03:21 -08002283 module.resume();
Andy Huibers10c58162014-03-29 14:06:54 -07002284 UsageStatistics.instance().changeScreen(currentUserInterfaceMode(),
2285 NavigationChange.InteractionCause.BUTTON);
Sascha Haeberling2d11fcf2014-03-13 09:04:32 -07002286 updatePreviewVisibility();
Doris Liu6432cd62013-06-13 17:20:31 -07002287 }
2288
2289 private void closeModule(CameraModule module) {
Angus Kongc4e66562013-11-22 23:03:21 -08002290 module.pause();
Erin Dahlgren5d187692014-02-25 19:16:12 -08002291 mCameraAppUI.clearModuleUI();
Angus Kong653c43b2013-08-21 18:28:43 -07002292 }
2293
Doris Liu742cd5b2013-09-12 16:17:43 -07002294 private void performDeletion() {
2295 if (!mPendingDeletion) {
2296 return;
2297 }
2298 hideUndoDeletionBar(false);
Sascha Haeberling44c1afb2013-12-20 11:59:35 -08002299 mDataAdapter.executeDeletion();
Doris Liu742cd5b2013-09-12 16:17:43 -07002300 }
2301
2302 public void showUndoDeletionBar() {
2303 if (mPendingDeletion) {
2304 performDeletion();
2305 }
2306 Log.v(TAG, "showing undo bar");
2307 mPendingDeletion = true;
Angus Kong653c43b2013-08-21 18:28:43 -07002308 if (mUndoDeletionBar == null) {
Angus Kong20fad242013-11-11 18:23:46 -08002309 ViewGroup v = (ViewGroup) getLayoutInflater().inflate(R.layout.undo_bar,
2310 mAboveFilmstripControlLayout, true);
Angus Kong653c43b2013-08-21 18:28:43 -07002311 mUndoDeletionBar = (ViewGroup) v.findViewById(R.id.camera_undo_deletion_bar);
2312 View button = mUndoDeletionBar.findViewById(R.id.camera_undo_deletion_button);
2313 button.setOnClickListener(new View.OnClickListener() {
2314 @Override
2315 public void onClick(View view) {
2316 mDataAdapter.undoDataRemoval();
Doris Liu742cd5b2013-09-12 16:17:43 -07002317 hideUndoDeletionBar(true);
2318 }
2319 });
2320 // Setting undo bar clickable to avoid touch events going through
2321 // the bar to the buttons (eg. edit button, etc) underneath the bar.
2322 mUndoDeletionBar.setClickable(true);
2323 // When there is user interaction going on with the undo button, we
2324 // do not want to hide the undo bar.
2325 button.setOnTouchListener(new View.OnTouchListener() {
2326 @Override
2327 public boolean onTouch(View v, MotionEvent event) {
2328 if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
2329 mIsUndoingDeletion = true;
2330 } else if (event.getActionMasked() == MotionEvent.ACTION_UP) {
Angus Kong20fad242013-11-11 18:23:46 -08002331 mIsUndoingDeletion = false;
Doris Liu742cd5b2013-09-12 16:17:43 -07002332 }
2333 return false;
Angus Kong653c43b2013-08-21 18:28:43 -07002334 }
2335 });
2336 }
2337 mUndoDeletionBar.setAlpha(0f);
2338 mUndoDeletionBar.setVisibility(View.VISIBLE);
Doris Liu742cd5b2013-09-12 16:17:43 -07002339 mUndoDeletionBar.animate().setDuration(200).alpha(1f).setListener(null).start();
Angus Kong653c43b2013-08-21 18:28:43 -07002340 }
2341
Doris Liu742cd5b2013-09-12 16:17:43 -07002342 private void hideUndoDeletionBar(boolean withAnimation) {
Angus Kong653c43b2013-08-21 18:28:43 -07002343 Log.v(TAG, "Hiding undo deletion bar");
Doris Liu742cd5b2013-09-12 16:17:43 -07002344 mPendingDeletion = false;
Angus Kong653c43b2013-08-21 18:28:43 -07002345 if (mUndoDeletionBar != null) {
Doris Liu742cd5b2013-09-12 16:17:43 -07002346 if (withAnimation) {
Angus Kong20fad242013-11-11 18:23:46 -08002347 mUndoDeletionBar.animate().setDuration(200).alpha(0f)
Doris Liu742cd5b2013-09-12 16:17:43 -07002348 .setListener(new Animator.AnimatorListener() {
2349 @Override
2350 public void onAnimationStart(Animator animation) {
2351 // Do nothing.
2352 }
2353
2354 @Override
2355 public void onAnimationEnd(Animator animation) {
2356 mUndoDeletionBar.setVisibility(View.GONE);
2357 }
2358
2359 @Override
2360 public void onAnimationCancel(Animator animation) {
2361 // Do nothing.
2362 }
2363
2364 @Override
2365 public void onAnimationRepeat(Animator animation) {
2366 // Do nothing.
2367 }
Angus Kong20fad242013-11-11 18:23:46 -08002368 }).start();
Doris Liu742cd5b2013-09-12 16:17:43 -07002369 } else {
2370 mUndoDeletionBar.setVisibility(View.GONE);
2371 }
Angus Kong653c43b2013-08-21 18:28:43 -07002372 }
Michael Kolb8872c232013-01-29 10:33:22 -08002373 }
2374
2375 @Override
Angus Kong9f1db522013-11-09 16:25:59 -08002376 public void onOrientationChanged(int orientation) {
2377 // We keep the last known orientation. So if the user first orient
2378 // the camera then point the camera to floor or sky, we still have
2379 // the correct orientation.
2380 if (orientation == OrientationManager.ORIENTATION_UNKNOWN) {
2381 return;
2382 }
2383 mLastRawOrientation = orientation;
2384 if (mCurrentModule != null) {
2385 mCurrentModule.onOrientationChanged(orientation);
2386 }
2387 }
2388
Angus Konga7194602013-09-06 17:20:15 -07002389 /**
Sascha Haeberlinga5a08d72013-09-11 20:30:52 -07002390 * Enable/disable swipe-to-filmstrip. Will always disable swipe if in
2391 * capture intent.
Angus Konga7194602013-09-06 17:20:15 -07002392 *
2393 * @param enable {@code true} to enable swipe.
2394 */
Doris Liu6432cd62013-06-13 17:20:31 -07002395 public void setSwipingEnabled(boolean enable) {
Angus Kong166e36f2013-12-03 08:54:42 -08002396 // TODO: Bring back the functionality.
Angus Konga7194602013-09-06 17:20:15 -07002397 if (isCaptureIntent()) {
Sascha Haeberling846d3ab2014-02-04 12:48:55 +01002398 // lockPreview(true);
Angus Konga7194602013-09-06 17:20:15 -07002399 } else {
Sascha Haeberling846d3ab2014-02-04 12:48:55 +01002400 // lockPreview(!enable);
Angus Konga7194602013-09-06 17:20:15 -07002401 }
Michael Kolb8872c232013-01-29 10:33:22 -08002402 }
2403
2404 // Accessor methods for getting latency times used in performance testing
Kevin Gabayana0e83472014-01-15 15:21:13 -08002405 public long getFirstPreviewTime() {
2406 if (mCurrentModule instanceof PhotoModule) {
2407 long coverHiddenTime = getCameraAppUI().getCoverHiddenTime();
2408 if (coverHiddenTime != -1) {
2409 return coverHiddenTime - mOnCreateTime;
2410 }
2411 }
2412 return -1;
2413 }
2414
Michael Kolb8872c232013-01-29 10:33:22 -08002415 public long getAutoFocusTime() {
2416 return (mCurrentModule instanceof PhotoModule) ?
2417 ((PhotoModule) mCurrentModule).mAutoFocusTime : -1;
2418 }
2419
2420 public long getShutterLag() {
2421 return (mCurrentModule instanceof PhotoModule) ?
2422 ((PhotoModule) mCurrentModule).mShutterLag : -1;
2423 }
2424
2425 public long getShutterToPictureDisplayedTime() {
2426 return (mCurrentModule instanceof PhotoModule) ?
2427 ((PhotoModule) mCurrentModule).mShutterToPictureDisplayedTime : -1;
2428 }
2429
2430 public long getPictureDisplayedToJpegCallbackTime() {
2431 return (mCurrentModule instanceof PhotoModule) ?
2432 ((PhotoModule) mCurrentModule).mPictureDisplayedToJpegCallbackTime : -1;
2433 }
2434
2435 public long getJpegCallbackFinishTime() {
2436 return (mCurrentModule instanceof PhotoModule) ?
2437 ((PhotoModule) mCurrentModule).mJpegCallbackFinishTime : -1;
2438 }
2439
2440 public long getCaptureStartTime() {
2441 return (mCurrentModule instanceof PhotoModule) ?
2442 ((PhotoModule) mCurrentModule).mCaptureStartTime : -1;
2443 }
2444
2445 public boolean isRecording() {
2446 return (mCurrentModule instanceof VideoModule) ?
2447 ((VideoModule) mCurrentModule).isRecording() : false;
2448 }
Angus Kong4f795b82013-09-16 14:25:35 -07002449
Sol Boucher5a344962014-06-17 14:05:08 -07002450 public CameraAgent.CameraOpenCallback getCameraOpenErrorCallback() {
Angus Kong20fad242013-11-11 18:23:46 -08002451 return mCameraController;
Angus Kong4f795b82013-09-16 14:25:35 -07002452 }
Ruben Brunkd217ed02013-10-08 23:31:13 -07002453
2454 // For debugging purposes only.
2455 public CameraModule getCurrentModule() {
2456 return mCurrentModule;
2457 }
Angus Kong13e87c42013-11-25 10:02:47 -08002458
Sascha Haeberlingc813ce12014-03-10 15:35:07 -07002459 @Override
2460 public void showTutorial(AbstractTutorialOverlay tutorial) {
2461 mCameraAppUI.showTutorial(tutorial, getLayoutInflater());
2462 }
2463
Sascha Haeberling0cf4a022014-07-31 11:36:58 -07002464 @Override
2465 public void showErrorAndFinish(int messageId) {
2466 CameraUtil.showErrorAndFinish(this, messageId);
2467 }
2468
Sascha Haeberlingde303232014-02-07 02:30:53 +01002469 /**
2470 * Reads the current location recording settings and passes it on to the
2471 * location manager.
2472 */
2473 public void syncLocationManagerSetting() {
Erin Dahlgren6190c362014-06-13 14:12:08 -07002474 Keys.syncLocationManager(mSettingsManager, mLocationManager);
Sascha Haeberlingde303232014-02-07 02:30:53 +01002475 }
2476
Angus Kong13e87c42013-11-25 10:02:47 -08002477 private void keepScreenOnForAWhile() {
2478 if (mKeepScreenOn) {
2479 return;
2480 }
2481 mMainHandler.removeMessages(MSG_CLEAR_SCREEN_ON_FLAG);
2482 getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
2483 mMainHandler.sendEmptyMessageDelayed(MSG_CLEAR_SCREEN_ON_FLAG, SCREEN_DELAY_MS);
2484 }
2485
2486 private void resetScreenOn() {
2487 mKeepScreenOn = false;
2488 mMainHandler.removeMessages(MSG_CLEAR_SCREEN_ON_FLAG);
2489 getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
2490 }
Angus Kongb2510252013-12-10 22:58:15 -08002491
Angus Kong6c0c7f12014-01-15 14:40:27 -08002492 /**
2493 * @return {@code true} if the Gallery is launched successfully.
2494 */
2495 private boolean startGallery() {
2496 if (mGalleryIntent == null) {
2497 return false;
2498 }
Angus Kongd3de1712013-12-12 22:01:12 -08002499 try {
Sascha Haeberlinga83ec8a2014-03-31 13:22:17 -07002500 UsageStatistics.instance().changeScreen(NavigationChange.Mode.GALLERY,
Andy Huibers10c58162014-03-29 14:06:54 -07002501 NavigationChange.InteractionCause.BUTTON);
Alan Newberger80461c22014-02-03 15:03:26 -08002502 Intent startGalleryIntent = new Intent(mGalleryIntent);
2503 int currentDataId = mFilmstripController.getCurrentId();
2504 LocalData currentLocalData = mDataAdapter.getLocalData(currentDataId);
2505 if (currentLocalData != null) {
Angus Kong571a8c32014-03-13 12:53:03 -07002506 GalleryHelper.setContentUri(startGalleryIntent, currentLocalData.getUri());
Alan Newberger80461c22014-02-03 15:03:26 -08002507 }
2508 launchActivityByIntent(startGalleryIntent);
Angus Kongd3de1712013-12-12 22:01:12 -08002509 } catch (ActivityNotFoundException e) {
2510 Log.w(TAG, "Failed to launch gallery activity, closing");
2511 }
Angus Kong6c0c7f12014-01-15 14:40:27 -08002512 return false;
Angus Kongd3de1712013-12-12 22:01:12 -08002513 }
2514
Angus Kong662fbf42013-12-12 13:22:03 -08002515 private void setNfcBeamPushUriFromData(LocalData data) {
Angus Kong571a8c32014-03-13 12:53:03 -07002516 final Uri uri = data.getUri();
Angus Kong662fbf42013-12-12 13:22:03 -08002517 if (uri != Uri.EMPTY) {
2518 mNfcPushUris[0] = uri;
2519 } else {
2520 mNfcPushUris[0] = null;
2521 }
2522 }
2523
Angus Kongb2510252013-12-10 22:58:15 -08002524 /**
Sascha Haeberlingd114a772014-02-28 21:27:27 -08002525 * Updates the visibility of the filmstrip bottom controls and action bar.
Angus Kongb2510252013-12-10 22:58:15 -08002526 */
2527 private void updateUiByData(final int dataId) {
Angus Kongb2510252013-12-10 22:58:15 -08002528 final LocalData currentData = mDataAdapter.getLocalData(dataId);
2529 if (currentData == null) {
2530 Log.w(TAG, "Current data ID not found.");
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08002531 hideSessionProgress();
Angus Kongb2510252013-12-10 22:58:15 -08002532 return;
2533 }
Sascha Haeberlingd114a772014-02-28 21:27:27 -08002534 updateActionBarMenu(currentData);
Angus Kongb2510252013-12-10 22:58:15 -08002535
Angus Kong001dc312014-02-27 16:58:11 -08002536 /* Bottom controls. */
2537 updateBottomControlsByData(currentData);
2538
2539 if (isSecureCamera()) {
2540 // We cannot show buttons in secure camera since go to other
2541 // activities might create a security hole.
2542 mCameraAppUI.getFilmstripBottomControls().hideControls();
2543 return;
2544 }
2545
2546
Angus Kong662fbf42013-12-12 13:22:03 -08002547 setNfcBeamPushUriFromData(currentData);
2548
Angus Konge2f4c032013-12-19 10:24:33 -08002549 if (!mDataAdapter.isMetadataUpdated(dataId)) {
Sascha Haeberling44c1afb2013-12-20 11:59:35 -08002550 mDataAdapter.updateMetadata(dataId);
Angus Konge2f4c032013-12-19 10:24:33 -08002551 }
2552 }
2553
2554 /**
2555 * Updates the bottom controls based on the data.
2556 */
2557 private void updateBottomControlsByData(final LocalData currentData) {
2558
Angus Kong7ae25c22014-02-25 10:37:39 -08002559 final CameraAppUI.BottomPanel filmstripBottomPanel =
Angus Kongb2510252013-12-10 22:58:15 -08002560 mCameraAppUI.getFilmstripBottomControls();
Angus Kong001dc312014-02-27 16:58:11 -08002561 filmstripBottomPanel.showControls();
Angus Kong7ae25c22014-02-25 10:37:39 -08002562 filmstripBottomPanel.setEditButtonVisibility(
Angus Kong740cbee2013-12-11 15:46:16 -08002563 currentData.isDataActionSupported(LocalData.DATA_ACTION_EDIT));
Angus Kong7ae25c22014-02-25 10:37:39 -08002564 filmstripBottomPanel.setShareButtonVisibility(
Angus Konge0aff892013-12-11 20:51:01 -08002565 currentData.isDataActionSupported(LocalData.DATA_ACTION_SHARE));
Angus Kong7ae25c22014-02-25 10:37:39 -08002566 filmstripBottomPanel.setDeleteButtonVisibility(
Angus Konge0aff892013-12-11 20:51:01 -08002567 currentData.isDataActionSupported(LocalData.DATA_ACTION_DELETE));
Angus Kongb2510252013-12-10 22:58:15 -08002568
2569 /* Progress bar */
2570
Angus Kong571a8c32014-03-13 12:53:03 -07002571 Uri contentUri = currentData.getUri();
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08002572 CaptureSessionManager sessionManager = getServices()
2573 .getCaptureSessionManager();
Sascha Haeberlinga63dbb62013-11-22 11:55:32 -08002574
Sascha Haeberling597c1a02014-03-06 11:46:06 -08002575 if (sessionManager.hasErrorMessage(contentUri)) {
2576 showProcessError(sessionManager.getErrorMesage(contentUri));
Angus Kongb2510252013-12-10 22:58:15 -08002577 } else {
Sascha Haeberling597c1a02014-03-06 11:46:06 -08002578 filmstripBottomPanel.hideProgressError();
Seth Raphaelcc79da22014-03-20 16:47:53 -07002579 CaptureSession session = sessionManager.getSession(contentUri);
Sascha Haeberling597c1a02014-03-06 11:46:06 -08002580
Seth Raphaelcc79da22014-03-20 16:47:53 -07002581 if (session != null) {
2582 int sessionProgress = session.getProgress();
2583
2584 if (sessionProgress < 0) {
2585 hideSessionProgress();
2586 } else {
2587 CharSequence progressMessage = session.getProgressMessage();
2588 showSessionProgress(progressMessage);
2589 updateSessionProgress(sessionProgress);
2590 }
Sascha Haeberling597c1a02014-03-06 11:46:06 -08002591 } else {
Seth Raphaelcc79da22014-03-20 16:47:53 -07002592 hideSessionProgress();
Sascha Haeberling597c1a02014-03-06 11:46:06 -08002593 }
Angus Kongb2510252013-12-10 22:58:15 -08002594 }
2595
2596 /* View button */
2597
2598 // We need to add this to a separate DB.
Angus Kong8a2350a2013-12-16 15:02:34 -08002599 final int viewButtonVisibility;
Sascha Haeberling7190c6a2014-02-21 10:11:31 -08002600 if (PanoramaMetadataLoader.isPanoramaAndUseViewer(currentData)) {
Angus Kong7ae25c22014-02-25 10:37:39 -08002601 viewButtonVisibility = CameraAppUI.BottomPanel.VIEWER_PHOTO_SPHERE;
Angus Kong8a2350a2013-12-16 15:02:34 -08002602 } else if (RgbzMetadataLoader.hasRGBZData(currentData)) {
Angus Kong7ae25c22014-02-25 10:37:39 -08002603 viewButtonVisibility = CameraAppUI.BottomPanel.VIEWER_REFOCUS;
Angus Kong8a2350a2013-12-16 15:02:34 -08002604 } else {
Angus Kong7ae25c22014-02-25 10:37:39 -08002605 viewButtonVisibility = CameraAppUI.BottomPanel.VIEWER_NONE;
Angus Kong8a2350a2013-12-16 15:02:34 -08002606 }
Angus Kongb2510252013-12-10 22:58:15 -08002607
Angus Kong7ae25c22014-02-25 10:37:39 -08002608 filmstripBottomPanel.setTinyPlanetEnabled(
Angus Kong8a2350a2013-12-16 15:02:34 -08002609 PanoramaMetadataLoader.isPanorama360(currentData));
Angus Kong7ae25c22014-02-25 10:37:39 -08002610 filmstripBottomPanel.setViewerButtonVisibility(viewButtonVisibility);
Angus Kongb2510252013-12-10 22:58:15 -08002611 }
Angus Kong50521172014-01-17 17:23:59 -08002612
2613 private class PeekAnimationHandler extends Handler {
2614 private class DataAndCallback {
2615 LocalData mData;
2616 com.android.camera.util.Callback<Bitmap> mCallback;
2617
2618 public DataAndCallback(LocalData data, com.android.camera.util.Callback<Bitmap>
2619 callback) {
2620 mData = data;
2621 mCallback = callback;
2622 }
2623 }
2624
2625 public PeekAnimationHandler(Looper looper) {
2626 super(looper);
2627 }
2628
2629 /**
2630 * Starts the animation decoding job and posts a {@code Runnable} back
2631 * when when the decoding is done.
2632 *
2633 * @param data The data item to decode the thumbnail for.
2634 * @param callback {@link com.android.camera.util.Callback} after the
2635 * decoding is done.
2636 */
Angus Kongc195e7a2014-02-20 16:56:37 -08002637 public void startDecodingJob(final LocalData data,
2638 final com.android.camera.util.Callback<Bitmap> callback) {
Angus Kong50521172014-01-17 17:23:59 -08002639 PeekAnimationHandler.this.obtainMessage(0 /** dummy integer **/,
2640 new DataAndCallback(data, callback)).sendToTarget();
2641 }
2642
2643 @Override
2644 public void handleMessage(Message msg) {
2645 final LocalData data = ((DataAndCallback) msg.obj).mData;
2646 final com.android.camera.util.Callback<Bitmap> callback =
2647 ((DataAndCallback) msg.obj).mCallback;
2648 if (data == null || callback == null) {
2649 return;
2650 }
2651
2652 final Bitmap bitmap;
2653 switch (data.getLocalDataType()) {
Angus Kong50521172014-01-17 17:23:59 -08002654 case LocalData.LOCAL_IN_PROGRESS_DATA:
Angus Kong571a8c32014-03-13 12:53:03 -07002655 byte[] jpegData = Storage.getJpegForSession(data.getUri());
2656 if (jpegData != null) {
2657 bitmap = BitmapFactory.decodeByteArray(jpegData, 0, jpegData.length);
2658 } else {
2659 bitmap = null;
2660 }
2661 break;
2662
2663 case LocalData.LOCAL_IMAGE:
Angus Kong50521172014-01-17 17:23:59 -08002664 FileInputStream stream;
2665 try {
2666 stream = new FileInputStream(data.getPath());
2667 } catch (FileNotFoundException e) {
2668 Log.e(TAG, "File not found:" + data.getPath());
2669 return;
2670 }
Angus Kongc195e7a2014-02-20 16:56:37 -08002671 Point dim = CameraUtil.resizeToFill(data.getWidth(), data.getHeight(),
2672 data.getRotation(), mAboveFilmstripControlLayout.getWidth(),
2673 mAboveFilmstripControlLayout.getMeasuredHeight());
2674 if (data.getRotation() % 180 != 0) {
2675 int dummy = dim.x;
2676 dim.x = dim.y;
2677 dim.y = dummy;
2678 }
Angus Kong50521172014-01-17 17:23:59 -08002679 bitmap = LocalDataUtil
2680 .loadImageThumbnailFromStream(stream, data.getWidth(), data.getHeight(),
Angus Kongc195e7a2014-02-20 16:56:37 -08002681 (int) (dim.x * 0.7f), (int) (dim.y * 0.7),
2682 data.getRotation(), MAX_PEEK_BITMAP_PIXELS);
Angus Kong50521172014-01-17 17:23:59 -08002683 break;
2684
2685 case LocalData.LOCAL_VIDEO:
2686 bitmap = LocalDataUtil.loadVideoThumbnail(data.getPath());
2687 break;
2688
2689 default:
2690 bitmap = null;
2691 break;
2692 }
2693
2694 if (bitmap == null) {
2695 return;
2696 }
2697
2698 mMainHandler.post(new Runnable() {
2699 @Override
2700 public void run() {
2701 callback.onCallback(bitmap);
Angus Kong50521172014-01-17 17:23:59 -08002702 }
2703 });
2704 }
2705 }
Sascha Haeberlingd114a772014-02-28 21:27:27 -08002706
2707 private void showDetailsDialog(int dataId) {
2708 final LocalData data = mDataAdapter.getLocalData(dataId);
2709 if (data == null) {
2710 return;
2711 }
2712 MediaDetails details = data.getMediaDetails(getAndroidContext());
2713 if (details == null) {
2714 return;
2715 }
2716 Dialog detailDialog = DetailsDialog.create(CameraActivity.this, details);
2717 detailDialog.show();
Andy Huibers10c58162014-03-29 14:06:54 -07002718 UsageStatistics.instance().mediaInteraction(
2719 fileNameFromDataID(dataId), MediaInteraction.InteractionType.DETAILS,
Andy Huibersebd95372014-05-12 14:44:13 -07002720 NavigationChange.InteractionCause.BUTTON, fileAgeFromDataID(dataId));
Sascha Haeberlingd114a772014-02-28 21:27:27 -08002721 }
2722
2723 /**
2724 * Show or hide action bar items depending on current data type.
2725 */
2726 private void updateActionBarMenu(LocalData data) {
2727 if (mActionBarMenu == null) {
2728 return;
2729 }
2730
2731 MenuItem detailsMenuItem = mActionBarMenu.findItem(R.id.action_details);
2732 if (detailsMenuItem == null) {
2733 return;
2734 }
2735
2736 int type = data.getLocalDataType();
2737 boolean showDetails = (type == LocalData.LOCAL_IMAGE) || (type == LocalData.LOCAL_VIDEO);
2738 detailsMenuItem.setVisible(showDetails);
2739 }
Michael Kolb8872c232013-01-29 10:33:22 -08002740}