blob: 965b541ec74d074c8f67f45ab2a9a481d622b2e3 [file] [log] [blame]
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.camera.util;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.provider.MediaStore;
import com.android.camera.debug.Log;
/**
* Workaround for secure-lockscreen double-onResume() bug:
* <p>
* If started from the secure-lockscreen, the activity may be quickly started,
* resumed, paused, stopped, and then started and resumed again. This is
* problematic for launch time from the secure-lockscreen because we typically open the
* camera in onResume() and close it in onPause(). These camera operations take
* a long time to complete. To workaround it, this class filters out
* high-frequency onResume()->onPause() sequences if the current intent
* indicates that we have started from the secure-lockscreen.
* </p>
* <p>
* Subclasses should override the appropriate on[Create|Start...]Tasks() method
* in place of the original.
* </p>
* <p>
* Sequences of onResume() followed quickly by onPause(), when the activity is
* started from a secure-lockscreen will result in a quick no-op.<br>
* </p>
*/
public abstract class QuickActivity extends Activity {
private static final Log.Tag TAG = new Log.Tag("QuickActivity");
/**
* The amount of time to wait before running onResumeTasks when started from
* the lockscreen.
*/
private static final long ON_RESUME_DELAY_MILLIS = 20;
/** A reference to the main handler on which to run lifecycle methods. */
private Handler mMainHandler;
private boolean mPaused;
/**
* True if the last call to onResume() resulted in a delayed call to
* mOnResumeTasks which was then canceled due to an immediate onPause().
* This allows optimizing the common case in which the subsequent
* call to onResume() should execute onResumeTasks() immediately.
*/
private boolean mCanceledResumeTasks = false;
/**
* A runnable for deferring tasks to be performed in onResume() if starting
* from the lockscreen.
*/
private final Runnable mOnResumeTasks = new Runnable() {
@Override
public void run() {
logLifecycle("onResumeTasks", true);
if (mPaused) {
onResumeTasks();
mPaused = false;
mCanceledResumeTasks = false;
}
logLifecycle("onResumeTasks", false);
}
};
@Override
protected final void onNewIntent(Intent intent) {
logLifecycle("onNewIntent", true);
Log.v(TAG, "Intent Action = " + intent.getAction());
setIntent(intent);
super.onNewIntent(intent);
onNewIntentTasks(intent);
logLifecycle("onNewIntent", false);
}
@Override
protected final void onCreate(Bundle bundle) {
logLifecycle("onCreate", true);
Log.v(TAG, "Intent Action = " + getIntent().getAction());
super.onCreate(bundle);
mMainHandler = new Handler(getMainLooper());
onCreateTasks(bundle);
mPaused = true;
logLifecycle("onCreate", false);
}
@Override
protected final void onStart() {
logLifecycle("onStart", true);
onStartTasks();
super.onStart();
logLifecycle("onStart", false);
}
@Override
protected final void onResume() {
logLifecycle("onResume", true);
mMainHandler.removeCallbacks(mOnResumeTasks);
if (delayOnResumeOnStart() && !mCanceledResumeTasks) {
mMainHandler.postDelayed(mOnResumeTasks, ON_RESUME_DELAY_MILLIS);
} else {
if (mPaused) {
onResumeTasks();
mPaused = false;
mCanceledResumeTasks = false;
}
}
super.onResume();
logLifecycle("onResume", false);
}
@Override
protected final void onPause() {
logLifecycle("onPause", true);
mMainHandler.removeCallbacks(mOnResumeTasks);
if (!mPaused) {
onPauseTasks();
mPaused = true;
} else {
mCanceledResumeTasks = true;
}
super.onPause();
logLifecycle("onPause", false);
}
@Override
protected final void onStop() {
if (isChangingConfigurations()) {
Log.v(TAG, "changing configurations");
}
logLifecycle("onStop", true);
onStopTasks();
super.onStop();
logLifecycle("onStop", false);
}
@Override
protected final void onRestart() {
logLifecycle("onRestart", true);
super.onRestart();
// TODO Support onRestartTasks() and handle the workaround for that too.
logLifecycle("onRestart", false);
}
@Override
protected final void onDestroy() {
logLifecycle("onDestroy", true);
onDestroyTasks();
super.onDestroy();
logLifecycle("onDestroy", false);
}
private void logLifecycle(String methodName, boolean start) {
String prefix = start ? "START" : "END";
Log.v(TAG, prefix + " " + methodName + ": Activity = " + toString());
}
private boolean delayOnResumeOnStart() {
String action = getIntent().getAction();
boolean isSecureLockscreenCamera =
action.equals(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE);
return isSecureLockscreenCamera;
}
/**
* Subclasses should override this in place of {@link Activity#onNewIntent}.
*/
protected void onNewIntentTasks(Intent newIntent) {
}
/**
* Subclasses should override this in place of {@link Activity#onCreate}.
*/
protected void onCreateTasks(Bundle savedInstanceState) {
}
/**
* Subclasses should override this in place of {@link Activity#onStart}.
*/
protected void onStartTasks() {
}
/**
* Subclasses should override this in place of {@link Activity#onResume}.
*/
protected void onResumeTasks() {
}
/**
* Subclasses should override this in place of {@link Activity#onPause}.
*/
protected void onPauseTasks() {
}
/**
* Subclasses should override this in place of {@link Activity#onStop}.
*/
protected void onStopTasks() {
}
/**
* Subclasses should override this in place of {@link Activity#onDestroy}.
*/
protected void onDestroyTasks() {
}
}