Home | History | Annotate | Download | only in util
      1 /*
      2  * Copyright (C) 2014 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 
     17 package com.android.camera.util;
     18 
     19 import android.app.Activity;
     20 import android.content.Intent;
     21 import android.os.Bundle;
     22 import android.os.Handler;
     23 import android.provider.MediaStore;
     24 
     25 import com.android.camera.debug.Log;
     26 
     27 /**
     28  * Workaround for secure-lockscreen double-onResume() bug:
     29  * <p>
     30  * If started from the secure-lockscreen, the activity may be quickly started,
     31  * resumed, paused, stopped, and then started and resumed again. This is
     32  * problematic for launch time from the secure-lockscreen because we typically open the
     33  * camera in onResume() and close it in onPause(). These camera operations take
     34  * a long time to complete. To workaround it, this class filters out
     35  * high-frequency onResume()->onPause() sequences if the current intent
     36  * indicates that we have started from the secure-lockscreen.
     37  * </p>
     38  * <p>
     39  * Subclasses should override the appropriate on[Create|Start...]Tasks() method
     40  * in place of the original.
     41  * </p>
     42  * <p>
     43  * Sequences of onResume() followed quickly by onPause(), when the activity is
     44  * started from a secure-lockscreen will result in a quick no-op.<br>
     45  * </p>
     46  */
     47 public abstract class QuickActivity extends Activity {
     48     private static final Log.Tag TAG = new Log.Tag("QuickActivity");
     49 
     50     /**
     51      * The amount of time to wait before running onResumeTasks when started from
     52      * the lockscreen.
     53      */
     54     private static final long ON_RESUME_DELAY_MILLIS = 20;
     55     /** A reference to the main handler on which to run lifecycle methods. */
     56     private Handler mMainHandler;
     57     private boolean mPaused;
     58     /**
     59      * True if the last call to onResume() resulted in a delayed call to
     60      * mOnResumeTasks which was then canceled due to an immediate onPause().
     61      * This allows optimizing the common case in which the subsequent
     62      * call to onResume() should execute onResumeTasks() immediately.
     63      */
     64     private boolean mCanceledResumeTasks = false;
     65 
     66     /**
     67      * A runnable for deferring tasks to be performed in onResume() if starting
     68      * from the lockscreen.
     69      */
     70     private final Runnable mOnResumeTasks = new Runnable() {
     71             @Override
     72         public void run() {
     73             logLifecycle("onResumeTasks", true);
     74             if (mPaused) {
     75                 onResumeTasks();
     76                 mPaused = false;
     77                 mCanceledResumeTasks = false;
     78             }
     79             logLifecycle("onResumeTasks", false);
     80         }
     81     };
     82 
     83     @Override
     84     protected final void onNewIntent(Intent intent) {
     85         logLifecycle("onNewIntent", true);
     86         Log.v(TAG, "Intent Action = " + intent.getAction());
     87         setIntent(intent);
     88         super.onNewIntent(intent);
     89         onNewIntentTasks(intent);
     90         logLifecycle("onNewIntent", false);
     91     }
     92 
     93     @Override
     94     protected final void onCreate(Bundle bundle) {
     95         logLifecycle("onCreate", true);
     96         Log.v(TAG, "Intent Action = " + getIntent().getAction());
     97         super.onCreate(bundle);
     98 
     99         mMainHandler = new Handler(getMainLooper());
    100 
    101         onCreateTasks(bundle);
    102 
    103         mPaused = true;
    104 
    105         logLifecycle("onCreate", false);
    106     }
    107 
    108     @Override
    109     protected final void onStart() {
    110         logLifecycle("onStart", true);
    111         onStartTasks();
    112         super.onStart();
    113         logLifecycle("onStart", false);
    114     }
    115 
    116     @Override
    117     protected final void onResume() {
    118         logLifecycle("onResume", true);
    119         mMainHandler.removeCallbacks(mOnResumeTasks);
    120         if (delayOnResumeOnStart() && !mCanceledResumeTasks) {
    121             mMainHandler.postDelayed(mOnResumeTasks, ON_RESUME_DELAY_MILLIS);
    122         } else {
    123             if (mPaused) {
    124                 onResumeTasks();
    125                 mPaused = false;
    126                 mCanceledResumeTasks = false;
    127             }
    128         }
    129         super.onResume();
    130         logLifecycle("onResume", false);
    131     }
    132 
    133     @Override
    134     protected final void onPause() {
    135         logLifecycle("onPause", true);
    136         mMainHandler.removeCallbacks(mOnResumeTasks);
    137         if (!mPaused) {
    138             onPauseTasks();
    139             mPaused = true;
    140         } else {
    141             mCanceledResumeTasks = true;
    142         }
    143         super.onPause();
    144         logLifecycle("onPause", false);
    145     }
    146 
    147     @Override
    148     protected final void onStop() {
    149         if (isChangingConfigurations()) {
    150             Log.v(TAG, "changing configurations");
    151         }
    152         logLifecycle("onStop", true);
    153         onStopTasks();
    154         super.onStop();
    155         logLifecycle("onStop", false);
    156     }
    157 
    158     @Override
    159     protected final void onRestart() {
    160         logLifecycle("onRestart", true);
    161         super.onRestart();
    162         // TODO Support onRestartTasks() and handle the workaround for that too.
    163         logLifecycle("onRestart", false);
    164     }
    165 
    166     @Override
    167     protected final void onDestroy() {
    168         logLifecycle("onDestroy", true);
    169         onDestroyTasks();
    170         super.onDestroy();
    171         logLifecycle("onDestroy", false);
    172     }
    173 
    174     private void logLifecycle(String methodName, boolean start) {
    175         String prefix = start ? "START" : "END";
    176         Log.v(TAG, prefix + " " + methodName + ": Activity = " + toString());
    177     }
    178 
    179     private boolean delayOnResumeOnStart() {
    180         String action = getIntent().getAction();
    181         boolean isSecureLockscreenCamera =
    182                 MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE.equals(action);
    183         return isSecureLockscreenCamera;
    184     }
    185 
    186     /**
    187      * Subclasses should override this in place of {@link Activity#onNewIntent}.
    188      */
    189     protected void onNewIntentTasks(Intent newIntent) {
    190     }
    191 
    192     /**
    193      * Subclasses should override this in place of {@link Activity#onCreate}.
    194      */
    195     protected void onCreateTasks(Bundle savedInstanceState) {
    196     }
    197 
    198     /**
    199      * Subclasses should override this in place of {@link Activity#onStart}.
    200      */
    201     protected void onStartTasks() {
    202     }
    203 
    204     /**
    205      * Subclasses should override this in place of {@link Activity#onResume}.
    206      */
    207     protected void onResumeTasks() {
    208     }
    209 
    210     /**
    211      * Subclasses should override this in place of {@link Activity#onPause}.
    212      */
    213     protected void onPauseTasks() {
    214     }
    215 
    216     /**
    217      * Subclasses should override this in place of {@link Activity#onStop}.
    218      */
    219     protected void onStopTasks() {
    220     }
    221 
    222     /**
    223      * Subclasses should override this in place of {@link Activity#onDestroy}.
    224      */
    225     protected void onDestroyTasks() {
    226     }
    227 }
    228