import android.animation.Animator;
import android.app.ActionBar;
+import android.app.Activity;
import android.app.Dialog;
import android.content.ActivityNotFoundException;
import android.content.BroadcastReceiver;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
-import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import android.provider.MediaStore;
import com.android.camera.app.MemoryManager;
import com.android.camera.app.MemoryQuery;
import com.android.camera.app.ModuleManager;
+import com.android.camera.app.ModuleManager.ModuleAgent;
import com.android.camera.app.ModuleManagerImpl;
import com.android.camera.app.MotionManager;
import com.android.camera.app.OrientationManager;
import com.android.camera.data.VideoDataFactory;
import com.android.camera.data.VideoItemFactory;
import com.android.camera.debug.Log;
+import com.android.camera.device.ActiveCameraDeviceTracker;
import com.android.camera.filmstrip.FilmstripContentPanel;
import com.android.camera.filmstrip.FilmstripController;
import com.android.camera.module.ModuleController;
import com.android.camera.module.ModulesInfo;
import com.android.camera.one.OneCameraException;
import com.android.camera.one.OneCameraManager;
+import com.android.camera.one.OneCameraModule;
+import com.android.camera.one.OneCameraOpener;
+import com.android.camera.one.config.OneCameraFeatureConfig;
+import com.android.camera.one.config.OneCameraFeatureConfigCreator;
import com.android.camera.session.CaptureSession;
import com.android.camera.session.CaptureSessionManager;
import com.android.camera.session.CaptureSessionManager.SessionListener;
import com.android.camera.settings.AppUpgrader;
import com.android.camera.settings.CameraSettingsActivity;
import com.android.camera.settings.Keys;
+import com.android.camera.settings.PictureSizeLoader;
import com.android.camera.settings.ResolutionSetting;
import com.android.camera.settings.ResolutionUtil;
import com.android.camera.settings.SettingsManager;
import com.android.camera.stats.UsageStatistics;
+import com.android.camera.stats.profiler.Profile;
+import com.android.camera.stats.profiler.Profiler;
+import com.android.camera.stats.profiler.Profilers;
import com.android.camera.tinyplanet.TinyPlanetFragment;
import com.android.camera.ui.AbstractTutorialOverlay;
import com.android.camera.ui.DetailsDialog;
import com.android.camera.ui.PreviewStatusListener;
import com.android.camera.util.ApiHelper;
import com.android.camera.util.Callback;
+import com.android.camera.util.CameraSettingsActivityHelper;
import com.android.camera.util.CameraUtil;
import com.android.camera.util.GalleryHelper;
import com.android.camera.util.GcamHelper;
import com.bumptech.glide.MemoryCategory;
import com.bumptech.glide.load.DecodeFormat;
import com.bumptech.glide.load.engine.executor.FifoPriorityThreadPoolExecutor;
-import com.bumptech.glide.load.engine.prefill.PreFillType;
import com.google.common.base.Optional;
import com.google.common.logging.eventprotos;
import com.google.common.logging.eventprotos.ForegroundEvent.ForegroundSource;
// panorama. If the extra is not set, it is in the normal camera mode.
public static final String SECURE_CAMERA_EXTRA = "secure_camera";
- public static final String MODULE_SCOPE_PREFIX = "_preferences_module_";
- public static final String CAMERA_SCOPE_PREFIX = "_preferences_camera_";
-
private static final int MSG_CLEAR_SCREEN_ON_FLAG = 2;
private static final long SCREEN_DELAY_MS = 2 * 60 * 1000; // 2 mins.
/** Load metadata for 10 items ahead of our current. */
private PhotoItemFactory mPhotoItemFactory;
private LocalFilmstripDataAdapter mDataAdapter;
- private OneCameraManager mCameraManager;
+ private ActiveCameraDeviceTracker mActiveCameraDeviceTracker;
+ private OneCameraOpener mOneCameraOpener;
+ private OneCameraManager mOneCameraManager;
private SettingsManager mSettingsManager;
private ResolutionSetting mResolutionSetting;
private ModeListView mModeListView;
private ViewGroup mUndoDeletionBar;
private boolean mIsUndoingDeletion = false;
private boolean mIsActivityRunning = false;
+ private FatalErrorHandler mFatalErrorHandler;
private final Uri[] mNfcPushUris = new Uri[1];
private boolean mPaused;
private CameraAppUI mCameraAppUI;
- private PeekAnimationHandler mPeekAnimationHandler;
- private HandlerThread mPeekAnimationThread;
-
private Intent mGalleryIntent;
private long mOnCreateTime;
/** Can be used to play custom sounds. */
private SoundPlayer mSoundPlayer;
+ /** Holds configuration for various OneCamera features. */
+ private OneCameraFeatureConfig mFeatureConfig;
+
private static final int LIGHTS_OUT_DELAY_MS = 4000;
private final int BASE_SYS_UI_VISIBILITY =
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
};
private MemoryManager mMemoryManager;
private MotionManager mMotionManager;
+ private final Profiler mProfiler = Profilers.instance().guard();
/** First run dialog */
private FirstRunDialog mFirstRunDialog;
@Override
public void onCameraDisabled(int cameraId) {
- UsageStatistics.instance().cameraFailure(
- eventprotos.CameraFailure.FailureReason.SECURITY, null,
- UsageStatistics.NONE, UsageStatistics.NONE);
Log.w(TAG, "Camera disabled: " + cameraId);
- CameraUtil.showErrorAndFinish(this, R.string.camera_disabled);
+ mFatalErrorHandler.onCameraDisabledFailure();
}
@Override
public void onDeviceOpenFailure(int cameraId, String info) {
- UsageStatistics.instance().cameraFailure(
- eventprotos.CameraFailure.FailureReason.OPEN_FAILURE, info,
- UsageStatistics.NONE, UsageStatistics.NONE);
Log.w(TAG, "Camera open failure: " + info);
- CameraUtil.showErrorAndFinish(this, R.string.cannot_connect_camera);
+ mFatalErrorHandler.onCameraOpenFailure();
}
@Override
public void onDeviceOpenedAlready(int cameraId, String info) {
Log.w(TAG, "Camera open already: " + cameraId + "," + info);
- CameraUtil.showErrorAndFinish(this, R.string.cannot_connect_camera);
+ mFatalErrorHandler.onGenericCameraAccessFailure();
}
@Override
public void onReconnectionFailure(CameraAgent mgr, String info) {
- UsageStatistics.instance().cameraFailure(
- eventprotos.CameraFailure.FailureReason.RECONNECT_FAILURE, null,
- UsageStatistics.NONE, UsageStatistics.NONE);
Log.w(TAG, "Camera reconnection failure:" + info);
- CameraUtil.showErrorAndFinish(this, R.string.cannot_connect_camera);
+ mFatalErrorHandler.onCameraReconnectFailure();
}
private static class MainHandler extends Handler {
mCameraAppUI.getFilmstripBottomControls().hideProgress();
}
- private void showSessionProgress(CharSequence message) {
+ private void showSessionProgress(int messageId) {
CameraAppUI.BottomPanel controls = mCameraAppUI.getFilmstripBottomControls();
- controls.setProgressText(message);
+ controls.setProgressText(messageId > 0 ? getString(messageId) : "");
controls.hideControls();
controls.hideProgressError();
controls.showProgress();
}
- private void showProcessError(CharSequence message) {
- mCameraAppUI.getFilmstripBottomControls().showProgressError(message);
+ private void showProcessError(int messageId) {
+ mCameraAppUI.getFilmstripBottomControls().showProgressError(
+ messageId > 0 ? getString(messageId) : "");
}
private void updateSessionProgress(int progress) {
mCameraAppUI.getFilmstripBottomControls().setProgress(progress);
}
- private void updateSessionProgressText(CharSequence message) {
- mCameraAppUI.getFilmstripBottomControls().setProgressText(message);
+ private void updateSessionProgressText(int messageId) {
+ mCameraAppUI.getFilmstripBottomControls().setProgressText(
+ messageId > 0 ? getString(messageId) : "");
}
private void setupNfcBeamPush() {
if (!Storage.isSessionUri(uri)) {
return;
}
- SessionItem newData = new SessionItem(getApplicationContext(), uri);
- mDataAdapter.addOrUpdate(newData);
+ Optional<SessionItem> newData = SessionItem.create(getApplicationContext(), uri);
+ if (newData.isPresent()) {
+ mDataAdapter.addOrUpdate(newData.get());
+ }
+ }
+
+ @Override
+ public void onSessionUpdated(Uri uri) {
+ Log.v(TAG, "onSessionUpdated: " + uri);
+ mDataAdapter.refresh(uri);
}
@Override
return;
}
- // Make the PhotoItem aware of the session placeholder, to
- // allow it to make a smooth transition to its content.
- newData.setSessionPlaceholderBitmap(
- Storage.getPlacerHolderForSession(sessionUri));
-
final int pos = mDataAdapter.findByContentUri(sessionUri);
if (pos == -1) {
// We do not have a placeholder for this image, perhaps
// due to the activity crashing or being killed.
mDataAdapter.addOrUpdate(newData);
} else {
+ // Make the PhotoItem aware of the session placeholder, to
+ // allow it to make a smooth transition to its content if it
+ // the session item is currently visible.
+ FilmstripItem oldSessionData = mDataAdapter.getFilmstripItemAt(pos);
+ if (mCameraAppUI.getFilmstripVisibility() == View.VISIBLE
+ && mFilmstripController.isVisible(oldSessionData)) {
+ Log.v(TAG, "session item visible, setting transition placeholder");
+ newData.setSessionPlaceholderBitmap(
+ Storage.getPlaceholderForSession(sessionUri));
+ }
mDataAdapter.updateItemAt(pos, newData);
}
}
}
@Override
- public void onSessionProgressText(final Uri uri, final CharSequence message) {
+ public void onSessionProgressText(final Uri uri, final int messageId) {
int currentIndex = mFilmstripController.getCurrentAdapterIndex();
if (currentIndex == -1) {
return;
}
if (uri.equals(
mDataAdapter.getItemAt(currentIndex).getData().getUri())) {
- updateSessionProgressText(message);
+ updateSessionProgressText(messageId);
}
}
@Override
- public void onSessionUpdated(Uri uri) {
- Log.v(TAG, "onSessionUpdated: " + uri);
- mDataAdapter.refresh(uri);
- }
-
- @Override
- public void onSessionPreviewAvailable(Uri uri) {
- Log.v(TAG, "onSessionPreviewAvailable: " + uri);
- mDataAdapter.refresh(uri);
- int index = mDataAdapter.findByContentUri(uri);
- if (index != -1) {
- startPeekAnimation(mDataAdapter.getItemAt(index),
- mCurrentModule.getPeekAccessibilityString());
+ public void onSessionCaptureIndicatorUpdate(Bitmap indicator, int rotationDegrees) {
+ // Don't show capture indicator in Photo Sphere.
+ final int photosphereModuleId = getApplicationContext().getResources()
+ .getInteger(
+ R.integer.camera_mode_photosphere);
+ if (mCurrentModeIndex == photosphereModuleId) {
+ return;
}
+ indicateCapture(indicator, rotationDegrees);
}
@Override
- public void onSessionFailed(Uri uri, CharSequence reason) {
+ public void onSessionFailed(Uri uri, int failureMessageId,
+ boolean removeFromFilmstrip) {
Log.v(TAG, "onSessionFailed:" + uri);
int failedIndex = mDataAdapter.findByContentUri(uri);
if (currentIndex == failedIndex) {
updateSessionProgress(0);
- showProcessError(reason);
+ showProcessError(failureMessageId);
+ mDataAdapter.refresh(uri);
+ }
+ if (removeFromFilmstrip) {
+ mFatalErrorHandler.onMediaStorageFailure();
+ mDataAdapter.removeAt(failedIndex);
}
- // HERE
- mDataAdapter.refresh(uri);
+ }
+
+ @Override
+ public void onSessionCanceled(Uri uri) {
+ Log.v(TAG, "onSessionCanceled:" + uri);
+ int failedIndex = mDataAdapter.findByContentUri(uri);
+ mDataAdapter.removeAt(failedIndex);
+ }
+
+ @Override
+ public void onSessionThumbnailUpdate(Bitmap bitmap) {
+ }
+
+ @Override
+ public void onSessionPictureDataUpdate(byte[] pictureData, int orientation) {
}
};
}
@Override
+ public OneCameraFeatureConfig getCameraFeatureConfig() {
+ return mFeatureConfig;
+ }
+
+ @Override
public Dialog createDialog() {
return new Dialog(this, android.R.style.Theme_Black_NoTitleBar_Fullscreen);
}
}
@Override
- public int getCurrentCameraId() {
- return mCameraController.getCurrentCameraId();
- }
-
- @Override
public String getModuleScope() {
- return MODULE_SCOPE_PREFIX + mCurrentModule.getModuleStringIdentifier();
+ ModuleAgent agent = mModuleManager.getModuleAgent(mCurrentModeIndex);
+ return SettingsManager.getModuleSettingScope(agent.getScopeNamespace());
}
@Override
public String getCameraScope() {
- int currentCameraId = getCurrentCameraId();
- if (currentCameraId < 0) {
- // if an unopen camera i.e. negative ID is returned, which we've observed in
- // some automated scenarios, just return it as a valid separate scope
- // this could cause user issues, so log a stack trace noting the call path
- // which resulted in this scenario.
- Log.w(TAG, "getting camera scope with no open camera, using id: " + currentCameraId);
- }
- return CAMERA_SCOPE_PREFIX + Integer.toString(currentCameraId);
+ // if an unopen camera i.e. negative ID is returned, which we've observed in
+ // some automated scenarios, just return it as a valid separate scope
+ // this could cause user issues, so log a stack trace noting the call path
+ // which resulted in this scenario.
+
+ return SettingsManager.getCameraSettingScope(
+ mCameraController.getCurrentCameraId().getValue());
}
@Override
}
/**
- * Starts the filmstrip peek animation if the filmstrip is not visible.
- *
- * @param data The data to peek.
- * @param accessibilityString Accessibility string to announce on peek animation.
+ * If not in filmstrip, this shows the capture indicator.
*/
- private void startPeekAnimation(final FilmstripItem data, final String accessibilityString) {
- if (mFilmstripVisible || mPeekAnimationHandler == null) {
- return;
- }
-
- if (!data.getAttributes().isImage() &&
- !data.getAttributes().isVideo() &&
- !data.getAttributes().isRendering()) {
+ private void indicateCapture(final Bitmap indicator, final int rotationDegrees) {
+ if (mFilmstripVisible) {
return;
}
if (mCurrentModeIndex == photosphereModuleId) {
return;
}
- mPeekAnimationHandler.startDecodingJob(data, new Callback<Bitmap>() {
+
+ mMainHandler.post(new Runnable() {
@Override
- public void onCallback(Bitmap result) {
- mCameraAppUI.startCaptureIndicatorRevealAnimation(accessibilityString);
- mCameraAppUI.updateCaptureIndicatorThumbnail(result, 0);
+ public void run() {
+ mCameraAppUI.startCaptureIndicatorRevealAnimation(mCurrentModule
+ .getPeekAccessibilityString());
+ mCameraAppUI.updateCaptureIndicatorThumbnail(indicator, rotationDegrees);
}
});
}
}
@Override
- protected void onPostExecute(FilmstripItem data) {
+ protected void onPostExecute(final FilmstripItem data) {
// TODO: Figure out why sometimes the data is aleady there.
mDataAdapter.addOrUpdate(data);
- startPeekAnimation(data, mCurrentModule.getPeekAccessibilityString());
+
+ // Legacy modules don't use CaptureSession, so we show the capture indicator when
+ // the item was safed.
+ if (mCurrentModule instanceof PhotoModule ||
+ mCurrentModule instanceof VideoModule) {
+ AsyncTask.THREAD_POOL_EXECUTOR.execute(new Runnable() {
+ @Override
+ public void run() {
+ final Optional<Bitmap> bitmap = data.generateThumbnail(
+ mAboveFilmstripControlLayout.getWidth(),
+ mAboveFilmstripControlLayout.getMeasuredHeight());
+ if (bitmap.isPresent()) {
+ indicateCapture(bitmap.get(), 0);
+ }
+ }
+ });
+ }
}
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, newData);
}
}
@Override
- public OneCameraManager getCameraManager() {
- return mCameraManager;
+ public OneCameraOpener getCameraOpener() {
+ return mOneCameraOpener;
}
private void removeItemAt(int index) {
Log.e(TAG, "Fatal error during onPause, call Activity.finish()");
finish();
} else {
- CameraUtil.showErrorAndFinish(CameraActivity.this,
- R.string.cannot_connect_camera);
+ mFatalErrorHandler.handleFatalError(FatalErrorHandler.Reason.CANNOT_CONNECT_TO_CAMERA);
}
}
};
@Override
public void onCreateTasks(Bundle state) {
+ Profile profile = mProfiler.create("CameraActivity.onCreateTasks").start();
CameraPerformanceTracker.onEvent(CameraPerformanceTracker.ACTIVITY_START);
+ mOnCreateTime = System.currentTimeMillis();
mAppContext = getApplicationContext();
+ mMainHandler = new MainHandler(this, getMainLooper());
+ mLocationManager = new LocationManager(mAppContext);
+ mOrientationManager = new OrientationManagerImpl(this, mMainHandler);
+ mSettingsManager = getServices().getSettingsManager();
+ mSoundPlayer = new SoundPlayer(mAppContext);
+ mFeatureConfig = OneCameraFeatureConfigCreator.createDefault(getContentResolver(),
+ getServices().getMemoryManager());
+ mFatalErrorHandler = new FatalErrorHandlerImpl(this);
+ profile.mark();
if (!Glide.isSetup()) {
Context context = getAndroidContext();
Glide.setup(new GlideBuilder(context)
// As a camera we will use a large amount of memory
// for displaying images.
glide.setMemoryCategory(MemoryCategory.HIGH);
-
- // Prefill glides bitmap pool to prevent excessive jank
- // when loading large images.
- glide.preFillBitmapPool(
- new PreFillType.Builder(GlideFilmstripManager.MAXIMUM_TEXTURE_SIZE)
- .setWeight(5),
- // It's more important for jank and GC to have
- // A larger weight of max texture size images than
- // media store sized images.
- new PreFillType.Builder(
- GlideFilmstripManager.MEDIASTORE_THUMB_WIDTH,
- GlideFilmstripManager.MEDIASTORE_THUMB_HEIGHT));
}
+ profile.mark("Glide.setup");
- mOnCreateTime = System.currentTimeMillis();
- mSoundPlayer = new SoundPlayer(mAppContext);
-
+ mActiveCameraDeviceTracker = ActiveCameraDeviceTracker.instance();
try {
- mCameraManager = OneCameraManager.get(this, ResolutionUtil.getDisplayMetrics(this));
+ mOneCameraOpener = OneCameraModule.provideOneCameraOpener(
+ mFeatureConfig,
+ mAppContext,
+ mActiveCameraDeviceTracker,
+ ResolutionUtil.getDisplayMetrics(this));
+ mOneCameraManager = OneCameraModule.provideOneCameraManager();
} catch (OneCameraException e) {
- // Log error and continue. Modules requiring OneCamera should check
- // and handle if null by showing error dialog or other treatment.
+ // Log error and continue start process while showing error dialog..
Log.e(TAG, "Creating camera manager failed.", e);
- CameraUtil.showErrorAndFinish(this, R.string.cannot_connect_camera);
+ mFatalErrorHandler.onGenericCameraAccessFailure();
}
+ profile.mark("OneCameraManager.get");
+
+ mCameraController = new CameraController(mAppContext, this, mMainHandler,
+ CameraAgentFactory.getAndroidCameraAgent(mAppContext,
+ CameraAgentFactory.CameraApi.API_1),
+ CameraAgentFactory.getAndroidCameraAgent(mAppContext,
+ CameraAgentFactory.CameraApi.AUTO),
+ mActiveCameraDeviceTracker);
+ mCameraController.setCameraExceptionHandler(
+ new CameraExceptionHandler(mCameraExceptionCallback, mMainHandler));
// TODO: Try to move all the resources allocation to happen as soon as
// possible so we can call module.init() at the earliest time.
mModuleManager = new ModuleManagerImpl();
- GcamHelper.init(getContentResolver());
- ModulesInfo.setupModules(mAppContext, mModuleManager);
- mSettingsManager = getServices().getSettingsManager();
+ ModulesInfo.setupModules(mAppContext, mModuleManager, mFeatureConfig);
+
AppUpgrader appUpgrader = new AppUpgrader(this);
appUpgrader.upgrade(mSettingsManager);
+
+ // Make sure the picture sizes are correctly cached for the current OS
+ // version.
+ profile.mark();
+ (new PictureSizeLoader(mAppContext)).computePictureSizes();
+ profile.mark("computePictureSizes");
Keys.setDefaults(mSettingsManager, mAppContext);
- mResolutionSetting = new ResolutionSetting(mSettingsManager, mCameraManager);
+
+ mResolutionSetting = new ResolutionSetting(mSettingsManager, mOneCameraManager,
+ getContentResolver());
getWindow().requestFeature(Window.FEATURE_ACTION_BAR);
// We suppress this flag via theme when drawing the system preview
if (ApiHelper.isLOrHigher()) {
getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
}
+
+ profile.mark();
setContentView(R.layout.activity_main);
+ profile.mark("setContentView()");
// A window background is set in styles.xml for the system to show a
// drawable background with gray color and camera icon before the
// activity is created. We set the background to null here to prevent
mActionBar.setBackgroundDrawable(new ColorDrawable(0x80000000));
}
- mMainHandler = new MainHandler(this, getMainLooper());
- mCameraController = new CameraController(mAppContext, this, mMainHandler,
- CameraAgentFactory.getAndroidCameraAgent(mAppContext,
- CameraAgentFactory.CameraApi.API_1),
- CameraAgentFactory.getAndroidCameraAgent(mAppContext,
- CameraAgentFactory.CameraApi.AUTO));
- mCameraController.setCameraExceptionHandler(
- new CameraExceptionHandler(mCameraExceptionCallback, mMainHandler));
-
mModeListView = (ModeListView) findViewById(R.id.mode_list_layout);
mModeListView.init(mModuleManager.getSupportedModeIndexList());
if (ApiHelper.HAS_ROTATION_ANIMATION) {
mFilmstripController = ((FilmstripView) findViewById(R.id.filmstrip_view)).getController();
mFilmstripController.setImageGap(
getResources().getDimensionPixelSize(R.dimen.camera_film_strip_gap));
+ profile.mark("Configure Camera UI");
+
mPanoramaViewHelper = new PanoramaViewHelper(this);
mPanoramaViewHelper.onCreate();
mCameraAppUI.setupClingForViewer(CameraAppUI.BottomPanel.VIEWER_REFOCUS);
}
- mLocationManager = new LocationManager(mAppContext);
- mOrientationManager = new OrientationManagerImpl(this, mMainHandler);
-
setModuleFromModeIndex(getModeIndex());
+
+ profile.mark();
mCameraAppUI.prepareModuleUI();
+ profile.mark("Init Current Module UI");
mCurrentModule.init(this, isSecureCamera(), isCaptureIntent());
+ profile.mark("Init CurrentModule");
if (!mSecureCamera) {
mFilmstripController.setDataAdapter(mDataAdapter);
MediaStore.Images.Media.EXTERNAL_CONTENT_URI, true,
mLocalImagesObserver);
getContentResolver().registerContentObserver(
- MediaStore.Video.Media.EXTERNAL_CONTENT_URI, true,
- mLocalVideosObserver);
+ MediaStore.Video.Media.EXTERNAL_CONTENT_URI, true,
+ mLocalVideosObserver);
+
mMemoryManager = getServices().getMemoryManager();
AsyncTask.THREAD_POOL_EXECUTOR.execute(new Runnable() {
public void run() {
HashMap memoryData = mMemoryManager.queryMemory();
UsageStatistics.instance().reportMemoryConsumed(memoryData,
- MemoryQuery.REPORT_LABEL_LAUNCH);
+ MemoryQuery.REPORT_LABEL_LAUNCH);
}
});
+
mMotionManager = getServices().getMotionManager();
- mFirstRunDialog = new FirstRunDialog(this, new FirstRunDialog.FirstRunDialogListener() {
+ mFirstRunDialog = new FirstRunDialog(this,
+ getAndroidContext(),
+ mResolutionSetting,
+ mSettingsManager,
+ mOneCameraManager,
+ new FirstRunDialog.FirstRunDialogListener() {
@Override
public void onFirstRunStateReady() {
+ // Make sure additional preferences have the correct resolution selected
+ CameraSettingsActivityHelper.verifyDefaults(getSettingsManager(),
+ getAndroidContext());
+
// Run normal resume tasks.
resume();
}
@Override
+ public void onFirstRunDialogCancelled() {
+ // App isn't functional until users finish first run dialog.
+ // We need to finish here since users hit back button during
+ // first run dialog (b/19593942).
+ finish();
+ }
+
+ @Override
public void onCameraAccessException() {
- CameraUtil.showErrorAndFinish(CameraActivity.this, R.string.cannot_connect_camera);
+ mFatalErrorHandler.onGenericCameraAccessFailure();
}
});
+ profile.stop();
}
/**
* Get the current mode index from the Intent or from persistent
* settings.
*/
- public int getModeIndex() {
+ private int getModeIndex() {
int modeIndex = -1;
int photoIndex = getResources().getInteger(R.integer.camera_mode_photo);
int videoIndex = getResources().getInteger(R.integer.camera_mode_video);
int gcamIndex = getResources().getInteger(R.integer.camera_mode_gcam);
- if (MediaStore.INTENT_ACTION_VIDEO_CAMERA.equals(getIntent().getAction())
- || MediaStore.ACTION_VIDEO_CAPTURE.equals(getIntent().getAction())) {
+ int captureIntentIndex =
+ getResources().getInteger(R.integer.camera_mode_capture_intent);
+ String intentAction = getIntent().getAction();
+ if (MediaStore.INTENT_ACTION_VIDEO_CAMERA.equals(intentAction)
+ || MediaStore.ACTION_VIDEO_CAPTURE.equals(intentAction)) {
modeIndex = videoIndex;
- } else if (MediaStore.ACTION_IMAGE_CAPTURE.equals(getIntent().getAction())) {
+ } else if (MediaStore.ACTION_IMAGE_CAPTURE.equals(intentAction)
+ || MediaStore.ACTION_IMAGE_CAPTURE_SECURE.equals(intentAction)) {
// Capture intent.
- modeIndex = photoIndex;
- } else if (MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA.equals(getIntent().getAction())
- ||MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE.equals(getIntent()
- .getAction())
- || MediaStore.ACTION_IMAGE_CAPTURE_SECURE.equals(getIntent().getAction())) {
+ modeIndex = captureIntentIndex;
+ } else if (MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA.equals(intentAction)
+ ||MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE.equals(intentAction)
+ || MediaStore.ACTION_IMAGE_CAPTURE_SECURE.equals(intentAction)) {
modeIndex = mSettingsManager.getInteger(SettingsManager.SCOPE_GLOBAL,
Keys.KEY_CAMERA_MODULE_LAST_USED);
modeIndex = mSettingsManager.getInteger(SettingsManager.SCOPE_GLOBAL,
Keys.KEY_STARTUP_MODULE_INDEX);
if ((modeIndex == gcamIndex &&
- !GcamHelper.hasGcamAsSeparateModule()) || modeIndex < 0) {
+ !GcamHelper.hasGcamAsSeparateModule(mFeatureConfig)) || modeIndex < 0) {
modeIndex = photoIndex;
}
}
@Override
public void onPauseTasks() {
CameraPerformanceTracker.onEvent(CameraPerformanceTracker.ACTIVITY_PAUSE);
+ Profile profile = mProfiler.create("CameraActivity.onPause").start();
/*
* Save the last module index after all secure camera and icon launches,
}
mPaused = true;
- if (mPeekAnimationHandler != null) {
- mPeekAnimationHandler = null;
- mPeekAnimationThread.quitSafely();
- mPeekAnimationThread = null;
- }
mCameraAppUI.hideCaptureIndicator();
mFirstRunDialog.dismiss();
Log.v(TAG, "onPause closing camera");
mCameraController.closeCamera(true);
}
+
+ profile.stop();
}
@Override
}
private void resume() {
+ Profile profile = mProfiler.create("CameraActivity.resume").start();
CameraPerformanceTracker.onEvent(CameraPerformanceTracker.ACTIVITY_RESUME);
Log.v(TAG, "Build info: " + Build.DISPLAY);
break;
}
}
- UsageStatistics.instance().foregrounded(source, currentUserInterfaceMode());
+ UsageStatistics.instance().foregrounded(source, currentUserInterfaceMode(),
+ isKeyguardSecure(), isKeyguardLocked(),
+ mStartupOnCreate, mExecutionStartNanoTime);
mGalleryIntent = IntentHelper.getGalleryIntent(mAppContext);
if (ApiHelper.isLOrHigher()) {
}
mOrientationManager.resume();
- mPeekAnimationThread = new HandlerThread("Peek animation");
- mPeekAnimationThread.start();
- mPeekAnimationHandler = new PeekAnimationHandler(mPeekAnimationThread.getLooper(),
- mMainHandler, mAboveFilmstripControlLayout);
mCurrentModule.hardResetSettings(mSettingsManager);
+
+ profile.mark();
mCurrentModule.resume();
UsageStatistics.instance().changeScreen(currentUserInterfaceMode(),
NavigationChange.InteractionCause.BUTTON);
setSwipingEnabled(true);
+ profile.mark("mCurrentModule.resume");
if (!mResetToPreviewOnResume) {
FilmstripItem item = mDataAdapter.getItemAt(
mDataAdapter.refresh(item.getData().getUri());
}
}
+
// The share button might be disabled to avoid double tapping.
mCameraAppUI.getFilmstripBottomControls().setShareEnabled(true);
// Default is showing the preview, unless disabled by explicitly
final View rootView = findViewById(R.id.activity_root_view);
mLightsOutRunnable.run();
getWindow().getDecorView().setOnSystemUiVisibilityChangeListener(
- new OnSystemUiVisibilityChangeListener() {
- @Override
- public void onSystemUiVisibilityChange(int visibility) {
- mMainHandler.removeCallbacks(mLightsOutRunnable);
- mMainHandler.postDelayed(mLightsOutRunnable, LIGHTS_OUT_DELAY_MS);
- }
- });
-
+ new OnSystemUiVisibilityChangeListener() {
+ @Override
+ public void onSystemUiVisibilityChange(int visibility) {
+ mMainHandler.removeCallbacks(mLightsOutRunnable);
+ mMainHandler.postDelayed(mLightsOutRunnable, LIGHTS_OUT_DELAY_MS);
+ }
+ });
+
+ profile.mark();
mPanoramaViewHelper.onResume();
- ReleaseHelper.showReleaseInfoDialogOnStart(this, mSettingsManager);
+ profile.mark("mPanoramaViewHelper.onResume()");
+ ReleaseHelper.showReleaseInfoDialogOnStart(this, mSettingsManager);
// Enable location recording if the setting is on.
final boolean locationRecordingEnabled =
mSettingsManager.getBoolean(SettingsManager.SCOPE_GLOBAL, Keys.KEY_RECORD_LOCATION);
updatePreviewRendering(previewVisibility);
mMotionManager.start();
+ profile.stop();
}
private void fillTemporarySessions() {
if (message != null) {
Log.w(TAG, "Storage warning: " + message);
if (mStorageHint == null) {
- mStorageHint = OnScreenHint.makeText(message);
+ mStorageHint = OnScreenHint.makeText(CameraActivity.this, message);
} else {
mStorageHint.setText(message);
}
public int getPreferredChildModeIndex(int modeIndex) {
if (modeIndex == getResources().getInteger(R.integer.camera_mode_photo)) {
boolean hdrPlusOn = Keys.isHdrPlusOn(mSettingsManager);
- if (hdrPlusOn && GcamHelper.hasGcamAsSeparateModule()) {
+ if (hdrPlusOn && GcamHelper.hasGcamAsSeparateModule(mFeatureConfig)) {
modeIndex = getResources().getInteger(R.integer.camera_mode_gcam);
}
}
mCameraController.closeCamera(true);
}
mCurrentModeIndex = agent.getModuleId();
- mCurrentModule = (CameraModule) agent.createModule(this);
+ mCurrentModule = (CameraModule) agent.createModule(this, getIntent());
}
@Override
return CameraServicesImpl.instance();
}
+ @Override
+ public FatalErrorHandler getFatalErrorHandler() {
+ return mFatalErrorHandler;
+ }
+
public List<String> getSupportedModeNames() {
List<Integer> indices = mModuleManager.getSupportedModeIndexList();
List<String> supported = new ArrayList<String>();
private void openModule(CameraModule module) {
module.init(this, isSecureCamera(), isCaptureIntent());
module.hardResetSettings(mSettingsManager);
+ // Hide accessibility zoom UI by default. Modules will enable it themselves if required.
+ getCameraAppUI().hideAccessibilityZoomUI();
if (!mPaused) {
module.resume();
UsageStatistics.instance().changeScreen(currentUserInterfaceMode(),
}
@Override
- public void showErrorAndFinish(int messageId) {
- CameraUtil.showErrorAndFinish(this, messageId);
+ public void finishActivityWithIntentCompleted(Intent resultIntent) {
+ finishActivityWithIntentResult(Activity.RESULT_OK, resultIntent);
}
+ @Override
+ public void finishActivityWithIntentCanceled() {
+ finishActivityWithIntentResult(Activity.RESULT_CANCELED, new Intent());
+ }
+
+ private void finishActivityWithIntentResult(int resultCode, Intent resultIntent) {
+ mResultCodeForTesting = resultCode;
+ mResultDataForTesting = resultIntent;
+ setResult(resultCode, resultIntent);
+ finish();
+ }
private void keepScreenOnForAWhile() {
if (mKeepScreenOn) {
.getCaptureSessionManager();
if (sessionManager.hasErrorMessage(contentUri)) {
- showProcessError(sessionManager.getErrorMesage(contentUri));
+ showProcessError(sessionManager.getErrorMessageId(contentUri));
} else {
filmstripBottomPanel.hideProgressError();
CaptureSession session = sessionManager.getSession(contentUri);
if (sessionProgress < 0) {
hideSessionProgress();
} else {
- CharSequence progressMessage = session.getProgressMessage();
- showSessionProgress(progressMessage);
+ int progressMessageId = session.getProgressMessageId();
+ showSessionProgress(progressMessageId);
updateSessionProgress(sessionProgress);
}
} else {
filmstripBottomPanel.setViewerButtonVisibility(viewButtonVisibility);
}
- private static class PeekAnimationHandler extends Handler {
- private class DataAndCallback {
- FilmstripItem mData;
- com.android.camera.util.Callback<Bitmap> mCallback;
-
- public DataAndCallback(FilmstripItem data, com.android.camera.util.Callback<Bitmap>
- callback) {
- mData = data;
- mCallback = callback;
- }
- }
-
- private final Handler mMainHandler;
- private final FrameLayout mAboveFilmstripControlLayout;
-
- public PeekAnimationHandler(Looper looper, Handler mainHandler,
- FrameLayout aboveFilmstripControlLayout) {
- super(looper);
- mMainHandler = mainHandler;
- mAboveFilmstripControlLayout = aboveFilmstripControlLayout;
- }
-
- /**
- * Starts the animation decoding job and posts a {@code Runnable} back
- * when when the decoding is done.
- *
- * @param data The data item to decode the thumbnail for.
- * @param callback {@link com.android.camera.util.Callback} after the
- * decoding is done.
- */
- public void startDecodingJob(final FilmstripItem data,
- final com.android.camera.util.Callback<Bitmap> callback) {
- PeekAnimationHandler.this.obtainMessage(0 /** dummy integer **/,
- new DataAndCallback(data, callback)).sendToTarget();
- }
-
- @Override
- public void handleMessage(Message msg) {
- final FilmstripItem data = ((DataAndCallback) msg.obj).mData;
- final com.android.camera.util.Callback<Bitmap> callback =
- ((DataAndCallback) msg.obj).mCallback;
- if (data == null || callback == null) {
- return;
- }
-
- final Optional<Bitmap> bitmap = data.generateThumbnail(
- mAboveFilmstripControlLayout.getWidth(),
- mAboveFilmstripControlLayout.getMeasuredHeight());
-
- if (bitmap.isPresent()) {
- mMainHandler.post(new Runnable() {
- @Override
- public void run() {
- callback.onCallback(bitmap.get());
- }
- });
- }
- }
- }
-
private void showDetailsDialog(int index) {
final FilmstripItem data = mDataAdapter.getItemAt(index);
if (data == null) {