Hide action bar after a timeout

Also make sure:
1) Action bar does not go away when the menu is showing
2) Extend the timeout if user swipe to a new image when action bar is visible
3) Hide action bar immediately when double-tap-to-zoom starts
4) Action bar persists in filmstrip mode (i.e. non-fullscreen mode)

Bug: 10750342
Change-Id: I820dc2b57ced61f91246fffe3fecc4e60ea187ca
diff --git a/src/com/android/camera/CameraActivity.java b/src/com/android/camera/CameraActivity.java
index 3b4d9f2..702de87 100644
--- a/src/com/android/camera/CameraActivity.java
+++ b/src/com/android/camera/CameraActivity.java
@@ -40,6 +40,8 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
 import android.preference.PreferenceManager;
 import android.provider.MediaStore;
 import android.provider.Settings;
@@ -86,7 +88,8 @@
 import static com.android.camera.CameraManager.CameraOpenErrorCallback;
 
 public class CameraActivity extends Activity
-        implements ModuleSwitcher.ModuleSwitchListener {
+        implements ModuleSwitcher.ModuleSwitchListener,
+        ActionBar.OnMenuVisibilityListener {
 
     private static final String TAG = "CAM_Activity";
 
@@ -118,6 +121,9 @@
      */
     public static final int REQ_CODE_DONT_SWITCH_TO_PREVIEW = 142;
 
+    private static final int HIDE_ACTION_BAR = 1;
+    private static final long SHOW_ACTION_BAR_TIMEOUT_MS = 3000;
+
     /** Whether onResume should reset the view to the preview. */
     private boolean mResetToPreviewOnResume = true;
 
@@ -162,6 +168,7 @@
     private PanoramaViewHelper mPanoramaViewHelper;
     private CameraPreviewData mCameraPreviewData;
     private ActionBar mActionBar;
+    private OnActionBarVisibilityListener mOnActionBarVisibilityListener = null;
     private Menu mActionBarMenu;
     private ViewGroup mUndoDeletionBar;
     private boolean mIsUndoingDeletion = false;
@@ -258,6 +265,28 @@
         }
     }
 
+    private class MainHandler extends Handler {
+        public MainHandler(Looper looper) {
+            super(looper);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            if (msg.what == HIDE_ACTION_BAR) {
+                removeMessages(HIDE_ACTION_BAR);
+                CameraActivity.this.setSystemBarsVisibility(false);
+            }
+        }
+    }
+
+    public interface OnActionBarVisibilityListener {
+        public void onActionBarVisibilityChanged(boolean isVisible);
+    }
+
+    public void setOnActionBarVisibilityListener(OnActionBarVisibilityListener listener) {
+        mOnActionBarVisibilityListener = listener;
+    }
+
     private static int getImmersiveFlags() {
         if (ApiHelper.HAS_HIDEYBARS) {
             return View.SYSTEM_UI_FLAG_IMMERSIVE
@@ -295,7 +324,14 @@
                 public void onDataFullScreenChange(int dataID, boolean full) {
                     boolean isCameraID = isCameraPreview(dataID);
                     if (!isCameraID) {
-                        setActionBarVisibilityAndLightsOut(full);
+                        if (!full) {
+                            // Always show action bar in filmstrip mode
+                            CameraActivity.this.setSystemBarsVisibility(true, false);
+                        } else if (mActionBar.isShowing()) {
+                            // Hide action bar after time out in full screen mode
+                            mMainHandler.sendEmptyMessageDelayed(HIDE_ACTION_BAR,
+                                    SHOW_ACTION_BAR_TIMEOUT_MS);
+                        }
                     }
                 }
 
@@ -318,6 +354,12 @@
 
                 @Override
                 public void onCurrentDataChanged(final int dataID, final boolean current) {
+                    // Delay hiding action bar if there is any user interaction
+                    if (mMainHandler.hasMessages(HIDE_ACTION_BAR)) {
+                        mMainHandler.removeMessages(HIDE_ACTION_BAR);
+                        mMainHandler.sendEmptyMessageDelayed(HIDE_ACTION_BAR,
+                                SHOW_ACTION_BAR_TIMEOUT_MS);
+                    }
                     runOnUiThread(new Runnable() {
                         @Override
                         public void run() {
@@ -332,7 +374,7 @@
                             if (!current) {
                                 if (isCameraID) {
                                     mCurrentModule.onPreviewFocusChanged(false);
-                                    setActionBarVisibilityAndLightsOut(false);
+                                    CameraActivity.this.setSystemBarsVisibility(true);
                                 }
                                 hidePanoStitchingProgress();
                             } else {
@@ -340,7 +382,7 @@
                                     mCurrentModule.onPreviewFocusChanged(true);
                                     // Don't show the action bar in Camera
                                     // preview.
-                                    setActionBarVisibilityAndLightsOut(true);
+                                    CameraActivity.this.setSystemBarsVisibility(false);
                                     if (mPendingDeletion) {
                                         performDeletion();
                                     }
@@ -367,20 +409,24 @@
                 }
 
                 @Override
-                public boolean onToggleActionBarVisibility(int dataID) {
+                public void onToggleSystemDecorsVisibility(int dataID) {
+                    // If action bar is showing, hide it immediately, otherwise
+                    // show action bar and hide it later
                     if (mActionBar.isShowing()) {
-                        setActionBarVisibilityAndLightsOut(true);
-                        return false;
+                        CameraActivity.this.setSystemBarsVisibility(false);
                     } else {
                         // Don't show the action bar if that is the camera preview.
                         boolean isCameraID = isCameraPreview(dataID);
                         if (!isCameraID) {
-                            setActionBarVisibilityAndLightsOut(false);
-                            return true;
+                            CameraActivity.this.setSystemBarsVisibility(true, true);
                         }
-                        return false;
                     }
                 }
+
+                @Override
+                public void setSystemDecorsVisibility(boolean visible) {
+                    CameraActivity.this.setSystemBarsVisibility(visible);
+                }
             };
 
     public void gotoGallery() {
@@ -388,18 +434,40 @@
     }
 
     /**
-     * If enabled, this hides the action bar and switches the system UI to
-     * lights-out mode.
+     * If {@param visible} is false, this hides the action bar and switches the system UI
+     * to lights-out mode.
      */
-    private void setActionBarVisibilityAndLightsOut(boolean enabled) {
-        int visibility = DEFAULT_SYSTEM_UI_VISIBILITY | (enabled ? IMMERSIVE_FLAGS
-                : View.SYSTEM_UI_FLAG_VISIBLE);
-        mAboveFilmstripControlLayout
-                .setSystemUiVisibility(visibility);
-        if (enabled) {
-            mActionBar.hide();
-        } else {
-            mActionBar.show();
+
+    private void setSystemBarsVisibility(boolean visible) {
+        setSystemBarsVisibility(visible, false);
+    }
+
+    /**
+     * If {@param visible} is false, this hides the action bar and switches the
+     * system UI to lights-out mode. If {@param hideLater} is true, a delayed message
+     * will be sent after a timeout to hide the action bar.
+     */
+    private void setSystemBarsVisibility(boolean visible, boolean hideLater) {
+        mMainHandler.removeMessages(HIDE_ACTION_BAR);
+        boolean currentlyVisible = mActionBar.isShowing();
+
+        if (visible != currentlyVisible) {
+            int visibility = DEFAULT_SYSTEM_UI_VISIBILITY | (visible ? View.SYSTEM_UI_FLAG_VISIBLE
+                    : IMMERSIVE_FLAGS);
+            mAboveFilmstripControlLayout.setSystemUiVisibility(visibility);
+            if (visible) {
+                mActionBar.show();
+            } else {
+                mActionBar.hide();
+            }
+            if (mOnActionBarVisibilityListener != null) {
+                mOnActionBarVisibilityListener.onActionBarVisibilityChanged(visible);
+            }
+        }
+
+        // Now delay hiding the bars
+        if (visible && hideLater) {
+            mMainHandler.sendEmptyMessageDelayed(HIDE_ACTION_BAR, SHOW_ACTION_BAR_TIMEOUT_MS);
         }
     }
 
@@ -488,6 +556,15 @@
         }
     }
 
+    @Override
+    public void onMenuVisibilityChanged(boolean isVisible) {
+        // If menu is showing, we need to make sure action bar does not go away.
+        mMainHandler.removeMessages(HIDE_ACTION_BAR);
+        if (!isVisible) {
+            mMainHandler.sendEmptyMessageDelayed(HIDE_ACTION_BAR, SHOW_ACTION_BAR_TIMEOUT_MS);
+        }
+    }
+
     /**
      * According to the data type, make the menu items for supported operations
      * visible.
@@ -806,10 +883,13 @@
         getWindow().requestFeature(Window.FEATURE_ACTION_BAR);
         setContentView(R.layout.camera_filmstrip);
         mActionBar = getActionBar();
+        mActionBar.addOnMenuVisibilityListener(this);
 
         if (ApiHelper.HAS_ROTATION_ANIMATION) {
             setRotationAnimation();
         }
+
+        mMainHandler = new MainHandler(getMainLooper());
         // Check if this is in the secure camera mode.
         Intent intent = getIntent();
         String action = intent.getAction();
@@ -844,7 +924,7 @@
         mAboveFilmstripControlLayout.setFitsSystemWindows(true);
         // Hide action bar first since we are in full screen mode first, and
         // switch the system UI to lights-out mode.
-        setActionBarVisibilityAndLightsOut(true);
+        this.setSystemBarsVisibility(false);
         mPanoramaManager = AppManagerFactory.getInstance(this)
                 .getPanoramaStitchingManager();
         mPanoramaManager.addTaskListener(mStitchingListener);
@@ -894,7 +974,6 @@
         mOrientationListener = new MyOrientationEventListener(this);
         setModuleFromIndex(moduleIndex);
         mCurrentModule.init(this, mCameraModuleRootView);
-        mMainHandler = new Handler(getMainLooper());
 
         if (!mSecureCamera) {
             mDataAdapter = mWrappedDataAdapter;
diff --git a/src/com/android/camera/ui/FilmStripView.java b/src/com/android/camera/ui/FilmStripView.java
index a2e3506..cbbc54e 100644
--- a/src/com/android/camera/ui/FilmStripView.java
+++ b/src/com/android/camera/ui/FilmStripView.java
@@ -349,9 +349,14 @@
          * Toggles the visibility of the ActionBar.
          *
          * @param dataID The ID of the image data.
-         * @return The ActionBar visibility after the toggle.
          */
-        public boolean onToggleActionBarVisibility(int dataID);
+        public void onToggleSystemDecorsVisibility(int dataID);
+
+        /**
+         * Sets the visibility of system decors, including action bar and nav bar
+         * @param visible The visibility of the system decors
+         */
+        public void setSystemDecorsVisibility(boolean visible);
     }
 
     /**
@@ -990,6 +995,7 @@
         if (mBottomControls == null) {
             mBottomControls = (FilmstripBottomControls) ((View) getParent())
                     .findViewById(R.id.filmstrip_bottom_controls);
+            mActivity.setOnActionBarVisibilityListener(mBottomControls);
             mBottomControls.setListener(this);
         }
 
@@ -2061,7 +2067,6 @@
 
             if (mListener != null) {
                 mListener.onDataFullScreenChange(mViewItem[mCurrentItem].getId(), false);
-                mBottomControls.setVisibility(View.VISIBLE);
             }
         }
 
@@ -2077,7 +2082,6 @@
         private void enterFullScreen() {
             if (mListener != null) {
                 mListener.onDataFullScreenChange(mViewItem[mCurrentItem].getId(), true);
-                mBottomControls.setVisibility(View.GONE);
             }
         }
 
@@ -2096,7 +2100,6 @@
         private void leaveFullScreen() {
             if (mListener != null) {
                 mListener.onDataFullScreenChange(mViewItem[mCurrentItem].getId(), false);
-                mBottomControls.setVisibility(View.VISIBLE);
             }
         }
 
@@ -2218,8 +2221,7 @@
                 if (centerItem != null) {
                     dataID = centerItem.getId();
                 }
-                boolean visible = mListener.onToggleActionBarVisibility(dataID);
-                mBottomControls.setVisibility(visible ? View.VISIBLE : View.GONE);
+                mListener.onToggleSystemDecorsVisibility(dataID);
                 return true;
             }
             return false;
@@ -2237,6 +2239,7 @@
             if (!mController.stopScrolling(false)) {
                 return false;
             }
+            mListener.setSystemDecorsVisibility(false);
             mController.zoomAt(current, x, y);
             return false;
         }
diff --git a/src/com/android/camera/ui/FilmstripBottomControls.java b/src/com/android/camera/ui/FilmstripBottomControls.java
index 149aa90..451bc92 100644
--- a/src/com/android/camera/ui/FilmstripBottomControls.java
+++ b/src/com/android/camera/ui/FilmstripBottomControls.java
@@ -22,13 +22,15 @@
 import android.widget.ImageButton;
 import android.widget.RelativeLayout;
 
+import com.android.camera.CameraActivity;
 import com.android.camera2.R;
 
 /**
  * Shows controls at the bottom of the screen for editing, viewing a photo
  * sphere image and creating a tiny planet from a photo sphere image.
  */
-public class FilmstripBottomControls extends RelativeLayout {
+public class FilmstripBottomControls extends RelativeLayout
+    implements CameraActivity.OnActionBarVisibilityListener {
 
     /**
      * Classes implementing this interface can listen for events on the bottom
@@ -137,4 +139,10 @@
             }
         });
     }
+
+    @Override
+    public void onActionBarVisibilityChanged(boolean isVisible) {
+        // TODO: Fade in and out
+        setVisibility(isVisible ? VISIBLE : INVISIBLE);
+    }
 }