Merge "Clean up orientation logging" into ub-camera-glacier
diff --git a/res/drawable-hdpi/btn_cling.9.png b/res/drawable-hdpi/btn_cling.9.png
index 5501632..96b7183 100644
--- a/res/drawable-hdpi/btn_cling.9.png
+++ b/res/drawable-hdpi/btn_cling.9.png
Binary files differ
diff --git a/res/drawable-hdpi/btn_cling_pressed.9.png b/res/drawable-hdpi/btn_cling_pressed.9.png
index e9ae75b..a81a776 100644
--- a/res/drawable-hdpi/btn_cling_pressed.9.png
+++ b/res/drawable-hdpi/btn_cling_pressed.9.png
Binary files differ
diff --git a/res/drawable-hdpi/stgs_cling.9.png b/res/drawable-hdpi/stgs_cling.9.png
new file mode 100644
index 0000000..5501632
--- /dev/null
+++ b/res/drawable-hdpi/stgs_cling.9.png
Binary files differ
diff --git a/res/drawable-hdpi/stgs_cling_pressed.9.png b/res/drawable-hdpi/stgs_cling_pressed.9.png
new file mode 100644
index 0000000..e9ae75b
--- /dev/null
+++ b/res/drawable-hdpi/stgs_cling_pressed.9.png
Binary files differ
diff --git a/res/drawable-mdpi/btn_cling.9.png b/res/drawable-mdpi/btn_cling.9.png
index b93d042..47355c0 100644
--- a/res/drawable-mdpi/btn_cling.9.png
+++ b/res/drawable-mdpi/btn_cling.9.png
Binary files differ
diff --git a/res/drawable-mdpi/btn_cling_pressed.9.png b/res/drawable-mdpi/btn_cling_pressed.9.png
index f6e370b..dee7b22 100644
--- a/res/drawable-mdpi/btn_cling_pressed.9.png
+++ b/res/drawable-mdpi/btn_cling_pressed.9.png
Binary files differ
diff --git a/res/drawable-mdpi/stgs_cling.9.png b/res/drawable-mdpi/stgs_cling.9.png
new file mode 100644
index 0000000..b93d042
--- /dev/null
+++ b/res/drawable-mdpi/stgs_cling.9.png
Binary files differ
diff --git a/res/drawable-mdpi/stgs_cling_pressed.9.png b/res/drawable-mdpi/stgs_cling_pressed.9.png
new file mode 100644
index 0000000..f6e370b
--- /dev/null
+++ b/res/drawable-mdpi/stgs_cling_pressed.9.png
Binary files differ
diff --git a/res/drawable-xhdpi/btn_cling.9.png b/res/drawable-xhdpi/btn_cling.9.png
index cce70b3..e4e3252 100644
--- a/res/drawable-xhdpi/btn_cling.9.png
+++ b/res/drawable-xhdpi/btn_cling.9.png
Binary files differ
diff --git a/res/drawable-xhdpi/btn_cling_pressed.9.png b/res/drawable-xhdpi/btn_cling_pressed.9.png
index efa0f1c..83fd9ca 100644
--- a/res/drawable-xhdpi/btn_cling_pressed.9.png
+++ b/res/drawable-xhdpi/btn_cling_pressed.9.png
Binary files differ
diff --git a/res/drawable-xhdpi/stgs_cling.9.png b/res/drawable-xhdpi/stgs_cling.9.png
new file mode 100644
index 0000000..cce70b3
--- /dev/null
+++ b/res/drawable-xhdpi/stgs_cling.9.png
Binary files differ
diff --git a/res/drawable-xhdpi/stgs_cling_pressed.9.png b/res/drawable-xhdpi/stgs_cling_pressed.9.png
new file mode 100644
index 0000000..efa0f1c
--- /dev/null
+++ b/res/drawable-xhdpi/stgs_cling_pressed.9.png
Binary files differ
diff --git a/res/drawable-xxhdpi/btn_cling.9.png b/res/drawable-xxhdpi/btn_cling.9.png
index ba016b2..b41788c 100644
--- a/res/drawable-xxhdpi/btn_cling.9.png
+++ b/res/drawable-xxhdpi/btn_cling.9.png
Binary files differ
diff --git a/res/drawable-xxhdpi/btn_cling_pressed.9.png b/res/drawable-xxhdpi/btn_cling_pressed.9.png
index 48e861a..3a95c15 100644
--- a/res/drawable-xxhdpi/btn_cling_pressed.9.png
+++ b/res/drawable-xxhdpi/btn_cling_pressed.9.png
Binary files differ
diff --git a/res/drawable-xxhdpi/stgs_cling.9.png b/res/drawable-xxhdpi/stgs_cling.9.png
new file mode 100644
index 0000000..ba016b2
--- /dev/null
+++ b/res/drawable-xxhdpi/stgs_cling.9.png
Binary files differ
diff --git a/res/drawable-xxhdpi/stgs_cling_pressed.9.png b/res/drawable-xxhdpi/stgs_cling_pressed.9.png
new file mode 100644
index 0000000..48e861a
--- /dev/null
+++ b/res/drawable-xxhdpi/stgs_cling_pressed.9.png
Binary files differ
diff --git a/res/drawable-xxxhdpi/btn_cling.9.png b/res/drawable-xxxhdpi/btn_cling.9.png
new file mode 100644
index 0000000..1400b86
--- /dev/null
+++ b/res/drawable-xxxhdpi/btn_cling.9.png
Binary files differ
diff --git a/res/drawable-xxxhdpi/btn_cling_pressed.9.png b/res/drawable-xxxhdpi/btn_cling_pressed.9.png
new file mode 100644
index 0000000..a6bcb12
--- /dev/null
+++ b/res/drawable-xxxhdpi/btn_cling_pressed.9.png
Binary files differ
diff --git a/res/drawable/settings_cling.xml b/res/drawable/settings_cling.xml
new file mode 100644
index 0000000..9d04a08
--- /dev/null
+++ b/res/drawable/settings_cling.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_pressed="true"
+          android:drawable="@drawable/stgs_cling_pressed" />
+    <item android:drawable="@drawable/stgs_cling" />
+</selector>
diff --git a/res/layout-land/location_dialog_content.xml b/res/layout-land/location_dialog_content.xml
index 07f00ee..2577f69 100644
--- a/res/layout-land/location_dialog_content.xml
+++ b/res/layout-land/location_dialog_content.xml
@@ -61,7 +61,8 @@
                 android:paddingRight="10dp"
                 android:text="@string/remember_location_prompt"
                 android:textColor="@color/dialog_text_color"
-                android:textSize="16sp" />
+                android:textSize="16sp"
+                android:lineSpacingExtra="1.9sp" />
             <Button
                 android:id="@+id/confirm_button"
                 style="@style/BlueButton"
diff --git a/res/layout-port/location_dialog_content.xml b/res/layout-port/location_dialog_content.xml
index caf7792..0e1e453 100644
--- a/res/layout-port/location_dialog_content.xml
+++ b/res/layout-port/location_dialog_content.xml
@@ -46,7 +46,8 @@
             android:paddingRight="10dp"
             android:text="@string/remember_location_prompt"
             android:textColor="@color/dialog_text_color"
-            android:textSize="16sp" />
+            android:textSize="16sp"
+            android:lineSpacingExtra="1.9sp" />
     </LinearLayout>
 
     <Button
diff --git a/res/layout/settings_cling.xml b/res/layout/settings_cling.xml
index 406a016..eaeb7c7 100644
--- a/res/layout/settings_cling.xml
+++ b/res/layout/settings_cling.xml
@@ -25,7 +25,7 @@
       android:layout_width="@dimen/settings_cling_width"
       android:layout_height="wrap_content"
       android:text="@string/settings_cling_text"
-      android:background="@drawable/btn_cling"
+      android:background="@drawable/settings_cling"
       android:textColor="@android:color/white"
       android:layout_gravity="top|left"/>
 </com.android.camera.widget.SettingsCling>
\ No newline at end of file
diff --git a/res/values/colors.xml b/res/values/colors.xml
index 0e5a9e5..2eee2ac 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -102,9 +102,11 @@
     <color name="focus_outer_ring_color">#4CFFFFFF</color>
     <color name="fullscreen_dialog_background_color">@color/main_color_global</color>
     <color name="dialog_button_color">#FF76A7F9</color>
-    <color name="dialog_text_color">@android:color/white</color>
+    <color name="dialog_text_color">@android:color/black</color>
 
     <color name="settings_cling_color">#2962FF</color>
 
     <color name="mode_icon_hover_highlight">#2DFFFFFF</color>
+    
+    <color name="blue_button_text_color">#00838F</color>
 </resources>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index ec1e7e0..ad38594 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -221,7 +221,7 @@
         <item name="android:layout_height">48dp</item>
         <item name="android:background">@drawable/button_cling</item>
         <item name="android:fontFamily">sans-serif-regular</item>
-        <item name="android:textColor">@android:color/white</item>
+        <item name="android:textColor">@color/blue_button_text_color</item>
         <item name="android:textSize">14sp</item>
         <item name="android:padding">12dp</item>
     </style>
diff --git a/src/com/android/camera/CameraActivity.java b/src/com/android/camera/CameraActivity.java
index 8b2a256..314840f 100644
--- a/src/com/android/camera/CameraActivity.java
+++ b/src/com/android/camera/CameraActivity.java
@@ -280,7 +280,10 @@
         return mModuleManager;
     }
 
-    // close activity when secure app passes lock screen or screen turns off
+    /**
+     * Close activity when secure app passes lock screen or screen turns
+     * off.
+     */
     private final BroadcastReceiver mShutdownReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
@@ -288,15 +291,6 @@
         }
     };
 
-    private final ActionBar.OnMenuVisibilityListener mOnMenuVisibilityListener =
-            new ActionBar.OnMenuVisibilityListener() {
-        @Override
-        public void onMenuVisibilityChanged(boolean isVisible) {
-            // TODO: Remove this or bring back the original implementation: cancel
-            // auto-hide actionbar.
-        }
-    };
-
     /**
      * Whether the screen is kept turned on.
      */
@@ -1320,6 +1314,10 @@
         }
     }
 
+    /**
+     * Note: Make sure this callback is unregistered properly when the activity
+     * is destroyed since we're otherwise leaking the Activity reference.
+     */
     private final CameraExceptionHandler.CameraExceptionCallback mCameraExceptionCallback
         = new CameraExceptionHandler.CameraExceptionCallback() {
                 @Override
@@ -1369,14 +1367,15 @@
     @Override
     public void onCreateTasks(Bundle state) {
         CameraPerformanceTracker.onEvent(CameraPerformanceTracker.ACTIVITY_START);
+        mAppContext = getApplication().getBaseContext();
+
         if (!Glide.isSetup()) {
-            Glide.setup(new GlideBuilder(this)
+            Glide.setup(new GlideBuilder(getAndroidContext())
                 .setResizeService(new FifoPriorityThreadPoolExecutor(2)));
-            Glide.get(this).setMemoryCategory(MemoryCategory.HIGH);
+            Glide.get(getAndroidContext()).setMemoryCategory(MemoryCategory.HIGH);
         }
 
         mOnCreateTime = System.currentTimeMillis();
-        mAppContext = getApplicationContext();
         mSoundPlayer = new SoundPlayer(mAppContext);
 
         try {
@@ -1408,12 +1407,13 @@
         } else {
             mActionBar.setBackgroundDrawable(new ColorDrawable(0x80000000));
         }
-        mActionBar.addOnMenuVisibilityListener(mOnMenuVisibilityListener);
 
         mMainHandler = new MainHandler(this, getMainLooper());
         mCameraController = new CameraController(mAppContext, this, mMainHandler,
-                CameraAgentFactory.getAndroidCameraAgent(this, CameraAgentFactory.CameraApi.API_1),
-                CameraAgentFactory.getAndroidCameraAgent(this, CameraAgentFactory.CameraApi.AUTO));
+                CameraAgentFactory.getAndroidCameraAgent(mAppContext,
+                        CameraAgentFactory.CameraApi.API_1),
+                CameraAgentFactory.getAndroidCameraAgent(mAppContext,
+                        CameraAgentFactory.CameraApi.AUTO));
         mCameraController.setCameraExceptionHandler(
                 new CameraExceptionHandler(mCameraExceptionCallback, mMainHandler));
 
@@ -1791,7 +1791,8 @@
         mOrientationManager.resume();
         mPeekAnimationThread = new HandlerThread("Peek animation");
         mPeekAnimationThread.start();
-        mPeekAnimationHandler = new PeekAnimationHandler(mPeekAnimationThread.getLooper());
+        mPeekAnimationHandler = new PeekAnimationHandler(mPeekAnimationThread.getLooper(),
+                mMainHandler, mAboveFilmstripControlLayout);
 
         mCurrentModule.hardResetSettings(mSettingsManager);
         mCurrentModule.resume();
@@ -1913,9 +1914,9 @@
         if (mSecureCamera) {
             unregisterReceiver(mShutdownReceiver);
         }
-        mActionBar.removeOnMenuVisibilityListener(mOnMenuVisibilityListener);
         mSettingsManager.removeAllListeners();
         mCameraController.removeCallbackReceiver();
+        mCameraController.setCameraExceptionHandler(null);
         getContentResolver().unregisterContentObserver(mLocalImagesObserver);
         getContentResolver().unregisterContentObserver(mLocalVideosObserver);
         getServices().getCaptureSessionManager().removeSessionListener(mSessionListener);
@@ -2713,7 +2714,7 @@
         filmstripBottomPanel.setViewerButtonVisibility(viewButtonVisibility);
     }
 
-    private class PeekAnimationHandler extends Handler {
+    private static class PeekAnimationHandler extends Handler {
         private class DataAndCallback {
             LocalData mData;
             com.android.camera.util.Callback<Bitmap> mCallback;
@@ -2725,8 +2726,14 @@
             }
         }
 
-        public PeekAnimationHandler(Looper looper) {
+        private final Handler mMainHandler;
+        private final FrameLayout mAboveFilmstripControlLayout;
+
+        public PeekAnimationHandler(Looper looper, Handler mainHandler,
+                FrameLayout aboveFilmstripControlLayout) {
             super(looper);
+            mMainHandler = mainHandler;
+            mAboveFilmstripControlLayout = aboveFilmstripControlLayout;
         }
 
         /**
diff --git a/src/com/android/camera/FocusOverlayManager.java b/src/com/android/camera/FocusOverlayManager.java
index 1c5e00a..4e4d54c 100644
--- a/src/com/android/camera/FocusOverlayManager.java
+++ b/src/com/android/camera/FocusOverlayManager.java
@@ -38,6 +38,7 @@
 import com.android.camera.util.UsageStatistics;
 import com.android.ex.camera2.portability.CameraCapabilities;
 
+import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -133,17 +134,33 @@
         public void setFocusParameters();
     }
 
-    private class MainHandler extends Handler {
-        public MainHandler(Looper looper) {
+    /**
+     * TODO: Refactor this so that we either don't need a handler or make
+     * mListener not be the activity.
+     */
+    private static class MainHandler extends Handler {
+        /**
+         * The outer mListener at the moment is actually the CameraActivity,
+         * which we would leak if we didn't break the GC path here using a
+         * WeakReference.
+         */
+        final WeakReference<FocusOverlayManager> mManager;
+        public MainHandler(FocusOverlayManager manager, Looper looper) {
             super(looper);
+            mManager = new WeakReference<FocusOverlayManager>(manager);
         }
 
         @Override
         public void handleMessage(Message msg) {
+            FocusOverlayManager manager = mManager.get();
+            if (manager == null) {
+                return;
+            }
+
             switch (msg.what) {
                 case RESET_TOUCH_FOCUS: {
-                    cancelAutoFocus();
-                    mListener.startFaceDetection();
+                    manager.cancelAutoFocus();
+                    manager.mListener.startFaceDetection();
                     break;
                 }
             }
@@ -155,7 +172,7 @@
             Listener listener, boolean mirror, Looper looper, FocusUI ui) {
         mAppController = appController;
         mSettingsManager = appController.getSettingsManager();
-        mHandler = new MainHandler(looper);
+        mHandler = new MainHandler(this, looper);
         mMatrix = new Matrix();
         mDefaultFocusModes = new ArrayList<CameraCapabilities.FocusMode>(defaultFocusModes);
         updateCapabilities(capabilities);
diff --git a/src/com/android/camera/PhotoModule.java b/src/com/android/camera/PhotoModule.java
index 18331b8..f5d697a 100644
--- a/src/com/android/camera/PhotoModule.java
+++ b/src/com/android/camera/PhotoModule.java
@@ -254,6 +254,9 @@
     private final float[] mR = new float[16];
     private int mHeading = -1;
 
+    /** Used to detect motion. We use this to release focus lock early. */
+    private MotionManager mMotionManager;
+
     /** True if all the parameters needed to start preview is ready. */
     private boolean mCameraPreviewParamsReady = false;
 
@@ -1661,9 +1664,9 @@
                     new FocusOverlayManager(mAppController, defaultFocusModes,
                             mCameraCapabilities, this, mMirror, mActivity.getMainLooper(),
                             mUI.getFocusUI());
-            MotionManager motionManager = getServices().getMotionManager();
-            if (motionManager != null) {
-                motionManager.addListener(mFocusManager);
+            mMotionManager = getServices().getMotionManager();
+            if (mMotionManager != null) {
+                mMotionManager.addListener(mFocusManager);
             }
         }
         mAppController.addPreviewAreaSizeChangedListener(mFocusManager);
@@ -1717,6 +1720,11 @@
         // Remove the messages and runnables in the queue.
         mHandler.removeCallbacksAndMessages(null);
 
+        if (mMotionManager != null) {
+            mMotionManager.removeListener(mFocusManager);
+            mMotionManager = null;
+        }
+
         closeCamera();
         mActivity.enableKeepScreenOn(false);
         mUI.onPause();
diff --git a/src/com/android/camera/one/OneCameraManager.java b/src/com/android/camera/one/OneCameraManager.java
index 7cd57ff..607e6a0 100644
--- a/src/com/android/camera/one/OneCameraManager.java
+++ b/src/com/android/camera/one/OneCameraManager.java
@@ -96,7 +96,7 @@
             int maxMemoryMB = activity.getServices().getMemoryManager()
                     .getMaxAllowedNativeMemoryAllocation();
             return new com.android.camera.one.v2.OneCameraManagerImpl(
-                    activity.getApplicationContext(), cameraManager, maxMemoryMB,
+                    activity.getAndroidContext(), cameraManager, maxMemoryMB,
                     displayMetrics, activity.getSoundPlayer());
         } else {
             return new com.android.camera.one.v1.OneCameraManagerImpl();
diff --git a/src/com/android/camera/widget/FilmstripView.java b/src/com/android/camera/widget/FilmstripView.java
index fbd0d03..70c2b86 100644
--- a/src/com/android/camera/widget/FilmstripView.java
+++ b/src/com/android/camera/widget/FilmstripView.java
@@ -813,7 +813,7 @@
 
         data.prepare();
         View recycled = getRecycledView(dataID);
-        View v = mDataAdapter.getView(mActivity, recycled, dataID);
+        View v = mDataAdapter.getView(mActivity.getAndroidContext(), recycled, dataID);
         if (v == null) {
             return null;
         }
@@ -1484,6 +1484,10 @@
                         getMeasuredWidth(), getMeasuredHeight());
         final int offsetX = dim.x + mViewGapInPixel;
         ViewItem viewItem = buildItemFromData(dataID);
+        if (viewItem == null) {
+            Log.w(TAG, "unable to build inserted item from data");
+            return;
+        }
 
         if (insertedItemId >= mCurrentItem) {
             if (insertedItemId == mCurrentItem) {
@@ -1898,7 +1902,7 @@
 
         MyController(Context context) {
             TimeInterpolator decelerateInterpolator = new DecelerateInterpolator(1.5f);
-            mScroller = new MyScroller(mActivity,
+            mScroller = new MyScroller(mActivity.getAndroidContext(),
                     new Handler(mActivity.getMainLooper()),
                     mScrollerListener, decelerateInterpolator);
             mCanStopScroll = true;
diff --git a/src/com/android/camera/widget/VideoRecordingHints.java b/src/com/android/camera/widget/VideoRecordingHints.java
index c931dfb..1c0b7a3 100644
--- a/src/com/android/camera/widget/VideoRecordingHints.java
+++ b/src/com/android/camera/widget/VideoRecordingHints.java
@@ -29,6 +29,8 @@
 import com.android.camera.util.CameraUtil;
 import com.android.camera2.R;
 
+import java.lang.ref.WeakReference;
+
 /**
  * This class is designed to show the video recording hint when device is held in
  * portrait before video recording. The rotation device indicator will start rotating
@@ -58,6 +60,87 @@
     private int mCenterY = UNSET;
     private int mLastOrientation = OrientationEventListener.ORIENTATION_UNKNOWN;
 
+    private static class RotationAnimatorListener implements Animator.AnimatorListener {
+        private final WeakReference<VideoRecordingHints> mHints;
+        private boolean mCanceled = false;
+
+        public RotationAnimatorListener(VideoRecordingHints hint) {
+            mHints = new WeakReference<VideoRecordingHints>(hint);
+        }
+
+        @Override
+        public void onAnimationStart(Animator animation) {
+            mCanceled = false;
+        }
+
+        @Override
+        public void onAnimationEnd(Animator animation) {
+            VideoRecordingHints hint = mHints.get();
+            if (hint == null) {
+                return;
+            }
+
+            hint.mRotation = ((int) hint.mRotation) % 360;
+            // If animation is canceled, do not restart it.
+            if (mCanceled) {
+                return;
+            }
+            hint.post(new Runnable() {
+                @Override
+                public void run() {
+                    VideoRecordingHints hint = mHints.get();
+                    if (hint != null) {
+                        hint.continueRotationAnimation();
+                    }
+                }
+            });
+        }
+
+        @Override
+        public void onAnimationCancel(Animator animation) {
+            mCanceled = true;
+        }
+
+        @Override
+        public void onAnimationRepeat(Animator animation) {
+            // Do nothing.
+        }
+    }
+
+    private static class AlphaAnimatorListener implements Animator.AnimatorListener {
+        private final WeakReference<VideoRecordingHints> mHints;
+        AlphaAnimatorListener(VideoRecordingHints hint) {
+            mHints = new WeakReference<VideoRecordingHints>(hint);
+        }
+
+        @Override
+        public void onAnimationStart(Animator animation) {
+            // Do nothing.
+        }
+
+        @Override
+        public void onAnimationEnd(Animator animation) {
+            VideoRecordingHints hint = mHints.get();
+            if (hint == null) {
+                return;
+            }
+
+            hint.invalidate();
+            hint.setAlpha(1f);
+            hint.mRotation = 0;
+        }
+
+        @Override
+        public void onAnimationCancel(Animator animation) {
+            // Do nothing.
+        }
+
+        @Override
+        public void onAnimationRepeat(Animator animation) {
+            // Do nothing.
+        }
+    }
+
     public VideoRecordingHints(Context context, AttributeSet attrs) {
         super(context, attrs);
         mRotateArrows = getResources().getDrawable(R.drawable.rotate_arrows);
@@ -80,64 +163,11 @@
             }
         });
 
-        mRotationAnimation.addListener(new Animator.AnimatorListener() {
-            private boolean mCanceled = false;
-            @Override
-            public void onAnimationStart(Animator animation) {
-                mCanceled = false;
-            }
-
-            @Override
-            public void onAnimationEnd(Animator animation) {
-                mRotation = ((int) mRotation) % 360;
-                // If animation is canceled, do not restart it.
-                if (mCanceled) {
-                    return;
-                }
-                post(new Runnable() {
-                    @Override
-                    public void run() {
-                        continueRotationAnimation();
-                    }
-                });
-            }
-
-            @Override
-            public void onAnimationCancel(Animator animation) {
-                mCanceled = true;
-            }
-
-            @Override
-            public void onAnimationRepeat(Animator animation) {
-                // Do nothing.
-            }
-        });
+        mRotationAnimation.addListener(new RotationAnimatorListener(this));
 
         mAlphaAnimator = ObjectAnimator.ofFloat(this, "alpha", 1f, 0f);
         mAlphaAnimator.setDuration(FADE_OUT_DURATION_MS);
-        mAlphaAnimator.addListener(new Animator.AnimatorListener() {
-            @Override
-            public void onAnimationStart(Animator animation) {
-                // Do nothing.
-            }
-
-            @Override
-            public void onAnimationEnd(Animator animation) {
-                invalidate();
-                setAlpha(1f);
-                mRotation = 0;
-            }
-
-            @Override
-            public void onAnimationCancel(Animator animation) {
-                // Do nothing.
-            }
-
-            @Override
-            public void onAnimationRepeat(Animator animation) {
-                // Do nothing.
-            }
-        });
+        mAlphaAnimator.addListener(new AlphaAnimatorListener(this));
         mIsDefaultToPortrait = CameraUtil.isDefaultToPortrait(context);
     }