Adding bouncer animation on PagedView. (Bug 7459660)

- Adding Remove text for translations.

Change-Id: Ic18188a2a3caa9dfde8785611242b1c9925f7b87
diff --git a/core/res/res/layout/keyguard_widget_remove_drop_target.xml b/core/res/res/layout/keyguard_widget_remove_drop_target.xml
index c4fe9e0..f9f40ab 100644
--- a/core/res/res/layout/keyguard_widget_remove_drop_target.xml
+++ b/core/res/res/layout/keyguard_widget_remove_drop_target.xml
@@ -24,9 +24,10 @@
     android:paddingRight="40dp"
     android:drawableLeft="@drawable/kg_widget_delete_drop_target"
     android:drawablePadding="4dp"
+    android:text="@string/kg_reordering_delete_drop_target_text"
     android:textColor="#FFF"
     android:textSize="13sp"
     android:shadowColor="#000"
     android:shadowDy="1.0"
     android:shadowRadius="1.0"
-    android:visibility="gone" />
\ No newline at end of file
+    android:visibility="gone" />
diff --git a/core/res/res/values-land/bools.xml b/core/res/res/values-land/bools.xml
index 85c64d9..a1dd2e4 100644
--- a/core/res/res/values-land/bools.xml
+++ b/core/res/res/values-land/bools.xml
@@ -16,6 +16,7 @@
 
 <resources>
     <bool name="kg_enable_camera_default_widget">false</bool>
+    <bool name="kg_top_align_page_shrink_on_bouncer_visible">true</bool>
     <bool name="kg_share_status_area">false</bool>
     <bool name="kg_sim_puk_account_full_screen">false</bool>
 </resources>
diff --git a/core/res/res/values-sw600dp/bools.xml b/core/res/res/values-sw600dp/bools.xml
index 72731f1..00f45c1 100644
--- a/core/res/res/values-sw600dp/bools.xml
+++ b/core/res/res/values-sw600dp/bools.xml
@@ -22,4 +22,5 @@
     <!-- No camera for you, tablet user -->
     <bool name="kg_enable_camera_default_widget">false</bool>
     <bool name="kg_center_small_widgets_vertically">true</bool>
+    <bool name="kg_top_align_page_shrink_on_bouncer_visible">false</bool>
 </resources>
diff --git a/core/res/res/values/bools.xml b/core/res/res/values/bools.xml
index b5a9023..457131a 100644
--- a/core/res/res/values/bools.xml
+++ b/core/res/res/values/bools.xml
@@ -17,6 +17,7 @@
 <resources>
     <bool name="kg_enable_camera_default_widget">true</bool>
     <bool name="kg_center_small_widgets_vertically">false</bool>
+    <bool name="kg_top_align_page_shrink_on_bouncer_visible">true</bool>
     <bool name="action_bar_embed_tabs">true</bool>
     <bool name="action_bar_embed_tabs_pre_jb">false</bool>
     <bool name="split_action_bar_is_narrow">true</bool>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 73b9021..9932d1e 100755
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -3970,6 +3970,8 @@
     <!-- Sequence of characters used to separate message strings in keyguard. Typically just em-dash
          with spaces on either side. [CHAR LIMIT=3] -->
     <string name="kg_text_message_separator" product="default">" \u2014 "</string>
+    <!-- The delete-widget drop target button text -->
+    <string name="kg_reordering_delete_drop_target_text">Remove</string>
 
     <!-- Message shown in dialog when user is attempting to set the music volume above the
     recommended maximum level for headphones -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 1d57c0b..cd21d80 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1215,6 +1215,7 @@
   <java-symbol type="bool" name="kg_enable_camera_default_widget" />
   <java-symbol type="bool" name="kg_share_status_area" />
   <java-symbol type="bool" name="kg_sim_puk_account_full_screen" />
+  <java-symbol type="bool" name="kg_top_align_page_shrink_on_bouncer_visible" />
   <java-symbol type="bool" name="target_honeycomb_needs_options_menu" />
   <java-symbol type="bool" name="kg_center_small_widgets_vertically" />
   <java-symbol type="color" name="kg_multi_user_text_active" />
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java
index 1f31482..f165b61 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java
@@ -162,9 +162,11 @@
         mAppWidgetContainer.setViewStateManager(mViewStateManager);
         mAppWidgetContainer.setLockPatternUtils(mLockPatternUtils);
 
+        ChallengeLayout challenge = slider != null ? slider :
+            (ChallengeLayout) findViewById(R.id.multi_pane_challenge);
+        challenge.setOnBouncerStateChangedListener(mViewStateManager);
         mViewStateManager.setPagedView(mAppWidgetContainer);
-        mViewStateManager.setChallengeLayout(slider != null ? slider :
-                (ChallengeLayout) findViewById(R.id.multi_pane_challenge));
+        mViewStateManager.setChallengeLayout(challenge);
         mSecurityViewContainer = (KeyguardSecurityViewFlipper) findViewById(R.id.view_flipper);
         mKeyguardSelectorView = (KeyguardSelectorView) findViewById(R.id.keyguard_selector_view);
         mViewStateManager.setSecurityViewContainer(mSecurityViewContainer);
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewStateManager.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewStateManager.java
index 969b65e..e53358b 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewStateManager.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewStateManager.java
@@ -19,7 +19,9 @@
 import android.os.Looper;
 import android.view.View;
 
-public class KeyguardViewStateManager implements SlidingChallengeLayout.OnChallengeScrolledListener {
+public class KeyguardViewStateManager implements
+        SlidingChallengeLayout.OnChallengeScrolledListener,
+        ChallengeLayout.OnBouncerStateChangedListener {
 
     private KeyguardWidgetPager mKeyguardWidgetPager;
     private ChallengeLayout mChallengeLayout;
@@ -196,6 +198,7 @@
     @Override
     public void onScrollStateChanged(int scrollState) {
         if (mKeyguardWidgetPager == null || mChallengeLayout == null) return;
+
         boolean challengeOverlapping = mChallengeLayout.isChallengeOverlapping();
 
         if (scrollState == SlidingChallengeLayout.SCROLL_STATE_IDLE) {
@@ -226,15 +229,24 @@
             KeyguardWidgetFrame frame = mKeyguardWidgetPager.getWidgetPageAt(mPageListeningToSlider);
             if (frame == null) return;
 
-            frame.showFrame(this);
+            // Skip showing the frame and shrinking the widget if we are
+            if (!mChallengeLayout.isBouncing()) {
+                frame.showFrame(this);
 
-            // As soon as the security begins sliding, the widget becomes small (if it wasn't
-            // small to begin with).
-            if (!frame.isSmall()) {
-                // We need to fetch the final page, in case the pages are in motion.
-                mPageListeningToSlider = mKeyguardWidgetPager.getNextPage();
-                frame.shrinkWidget();
+                // As soon as the security begins sliding, the widget becomes small (if it wasn't
+                // small to begin with).
+                if (!frame.isSmall()) {
+                    // We need to fetch the final page, in case the pages are in motion.
+                    mPageListeningToSlider = mKeyguardWidgetPager.getNextPage();
+                    frame.shrinkWidget();
+                }
+            } else {
+                if (!frame.isSmall()) {
+                    // We need to fetch the final page, in case the pages are in motion.
+                    mPageListeningToSlider = mKeyguardWidgetPager.getNextPage();
+                }
             }
+
             // View is on the move.  Pause the security view until it completes.
             mKeyguardSecurityContainer.onPause();
         }
@@ -279,4 +291,14 @@
     public int getTransportState() {
         return mTransportState;
     }
+
+    // ChallengeLayout.OnBouncerStateChangedListener
+    @Override
+    public void onBouncerStateChanged(boolean bouncerActive) {
+        if (bouncerActive) {
+            mKeyguardWidgetPager.zoomOutToBouncer();
+        } else {
+            mKeyguardWidgetPager.zoomInFromBouncer();
+        }
+    }
 }
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetPager.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetPager.java
index fca347f..274e12b 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetPager.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetPager.java
@@ -44,7 +44,7 @@
 import java.util.ArrayList;
 
 public class KeyguardWidgetPager extends PagedView implements PagedView.PageSwitchListener,
-        OnLongClickListener {
+        OnLongClickListener, ChallengeLayout.OnBouncerStateChangedListener {
 
     ZInterpolator mZInterpolator = new ZInterpolator(0.5f);
     private static float CAMERA_DISTANCE = 10000;
@@ -73,6 +73,10 @@
 
     private int mWidgetToResetAfterFadeOut;
 
+    // Bouncer
+    protected int BOUNCER_ZOOM_IN_OUT_DURATION = 250;
+    private float BOUNCER_SCALE_FACTOR = 0.67f;
+
     // Background worker thread: used here for persistence, also made available to widget frames
     private final HandlerThread mBackgroundWorkerThread;
     private final Handler mBackgroundWorkerHandler;
@@ -712,4 +716,46 @@
         KeyguardWidgetFrame child = getWidgetPageAt(viewIndex);
         child.setIsHoveringOverDeleteDropTarget(isHovering);
     }
+
+    // ChallengeLayout.OnBouncerStateChangedListener
+    @Override
+    public void onBouncerStateChanged(boolean bouncerActive) {
+        if (bouncerActive) {
+            zoomOutToBouncer();
+        } else {
+            zoomInFromBouncer();
+        }
+    }
+
+    // Zoom in after the bouncer is dismissed
+    void zoomInFromBouncer() {
+        if (mZoomInOutAnim != null && mZoomInOutAnim.isRunning()) {
+            mZoomInOutAnim.cancel();
+        }
+        final View currentPage = getPageAt(getCurrentPage());
+        if (currentPage.getScaleX() < 1f || currentPage.getScaleY() < 1f) {
+            mZoomInOutAnim = new AnimatorSet();
+            mZoomInOutAnim.setDuration(BOUNCER_ZOOM_IN_OUT_DURATION);
+            mZoomInOutAnim.playTogether(
+                    ObjectAnimator.ofFloat(currentPage, "scaleX", 1f),
+                    ObjectAnimator.ofFloat(currentPage , "scaleY", 1f));
+            mZoomInOutAnim.start();
+        }
+    }
+
+    // Zoom out after the bouncer is initiated
+    void zoomOutToBouncer() {
+        if (mZoomInOutAnim != null && mZoomInOutAnim.isRunning()) {
+            mZoomInOutAnim.cancel();
+        }
+        View currentPage = getPageAt(getCurrentPage());
+        if (!(currentPage.getScaleX() < 1f || currentPage.getScaleY() < 1f)) {
+            mZoomInOutAnim = new AnimatorSet();
+            mZoomInOutAnim.setDuration(BOUNCER_ZOOM_IN_OUT_DURATION);
+            mZoomInOutAnim.playTogether(
+                    ObjectAnimator.ofFloat(currentPage, "scaleX", BOUNCER_SCALE_FACTOR),
+                    ObjectAnimator.ofFloat(currentPage, "scaleY", BOUNCER_SCALE_FACTOR));
+            mZoomInOutAnim.start();
+        }
+    }
 }
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/PagedView.java b/policy/src/com/android/internal/policy/impl/keyguard/PagedView.java
index 00a0aed..8f47578 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/PagedView.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/PagedView.java
@@ -24,6 +24,7 @@
 import android.animation.ValueAnimator;
 import android.animation.ValueAnimator.AnimatorUpdateListener;
 import android.content.Context;
+import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.graphics.Canvas;
 import android.graphics.Matrix;
@@ -209,7 +210,7 @@
     private long REORDERING_DELETE_DROP_TARGET_FADE_DURATION = 150;
     private float mMinScale = 1f;
     protected View mDragView;
-    private AnimatorSet mZoomInOutAnim;
+    protected AnimatorSet mZoomInOutAnim;
     private Runnable mSidePageHoverRunnable;
     private int mSidePageHoverIndex = -1;
     // This variable's scope is only for the duration of startReordering() and endReordering()
@@ -246,6 +247,9 @@
     // Drop to delete
     private View mDeleteDropTarget;
 
+    // Bouncer
+    private boolean mTopAlignPageWhenShrinkingForBouncer = false;
+
     public interface PageSwitchListener {
         void onPageSwitching(View newPage, int newPageIndex);
         void onPageSwitched(View newPage, int newPageIndex);
@@ -270,8 +274,10 @@
                 a.getDimensionPixelSize(R.styleable.PagedView_scrollIndicatorPaddingRight, 0);
         a.recycle();
 
-        mEdgeSwipeRegionSize =
-                getResources().getDimensionPixelSize(R.dimen.kg_edge_swipe_region_size);
+        Resources r = getResources();
+        mEdgeSwipeRegionSize = r.getDimensionPixelSize(R.dimen.kg_edge_swipe_region_size);
+        mTopAlignPageWhenShrinkingForBouncer =
+                r.getBoolean(R.bool.kg_top_align_page_shrink_on_bouncer_visible);
 
         setHapticFeedbackEnabled(false);
         init();
@@ -645,6 +651,10 @@
                 MeasureSpec.makeMeasureSpec(heightSize - verticalPadding, childHeightMode);
 
             child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
+            if (mTopAlignPageWhenShrinkingForBouncer) {
+                child.setPivotX(child.getWidth() / 2);
+                child.setPivotY(0f);
+            }
         }
         setMeasuredDimension(scaledWidthSize, scaledHeightSize);
 
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/SlidingChallengeLayout.java b/policy/src/com/android/internal/policy/impl/keyguard/SlidingChallengeLayout.java
index 7a71d8c..16ec8c5 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/SlidingChallengeLayout.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/SlidingChallengeLayout.java
@@ -532,8 +532,8 @@
     @Override
     public void showBouncer() {
         if (mIsBouncing) return;
-        showChallenge(true);
         mIsBouncing = true;
+        showChallenge(true);
         if (mScrimView != null) {
             mScrimView.setVisibility(VISIBLE);
         }