Merge "Cleanup dialpad show/hide logic."
diff --git a/res/anim/slide_in.xml b/res/anim/slide_in.xml
index b2ebf7d..9f9c4d4 100644
--- a/res/anim/slide_in.xml
+++ b/res/anim/slide_in.xml
@@ -13,10 +13,8 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
+<translate xmlns:android="http://schemas.android.com/apk/res/android"
     android:interpolator="@android:interpolator/fast_out_slow_in"
-    android:valueFrom="0.67"
-    android:valueTo="0"
-    android:valueType="floatType"
-    android:propertyName="yFraction"
-    android:duration="666" />
\ No newline at end of file
+    android:duration="666"
+    android:fromYDelta="67%p"
+    android:toYDelta="0" />
\ No newline at end of file
diff --git a/res/anim/slide_out.xml b/res/anim/slide_out.xml
index d3b92e3..e77bcde 100644
--- a/res/anim/slide_out.xml
+++ b/res/anim/slide_out.xml
@@ -13,10 +13,8 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
+<translate xmlns:android="http://schemas.android.com/apk/res/android"
     android:interpolator="@android:interpolator/fast_out_slow_in"
-    android:valueFrom="0"
-    android:valueTo="0.8"
-    android:valueType="floatType"
-    android:propertyName="yFraction"
-    android:duration="429" />
\ No newline at end of file
+    android:duration="429"
+    android:fromYDelta="0"
+    android:toYDelta="80%p" />
\ No newline at end of file
diff --git a/src/com/android/dialer/DialtactsActivity.java b/src/com/android/dialer/DialtactsActivity.java
index 8d14f01..ea1f60c 100644
--- a/src/com/android/dialer/DialtactsActivity.java
+++ b/src/com/android/dialer/DialtactsActivity.java
@@ -49,6 +49,9 @@
 import android.view.View;
 import android.view.View.OnDragListener;
 import android.view.animation.AccelerateInterpolator;
+import android.view.animation.Animation;
+import android.view.animation.Animation.AnimationListener;
+import android.view.animation.AnimationUtils;
 import android.view.animation.DecelerateInterpolator;
 import android.view.animation.Interpolator;
 import android.view.inputmethod.InputMethodManager;
@@ -163,7 +166,7 @@
     private boolean mInDialpadSearch;
     private boolean mInRegularSearch;
     private boolean mClearSearchOnPause;
-    private boolean isDialpadShown;
+    private boolean mIsDialpadShown;
 
     /**
      * The position of the currently selected tab in the attached {@link ListsFragment}.
@@ -257,7 +260,7 @@
                 if (DEBUG) {
                     Log.d(TAG, "onTextChange for mSearchView called with new query: " + newText);
                 }
-                final boolean dialpadSearch = isDialpadShowing();
+                final boolean dialpadSearch = mIsDialpadShown;
 
                 // Show search result with non-empty text. Show a bare list otherwise.
                 if (TextUtils.isEmpty(newText) && getInSearchUi()) {
@@ -291,10 +294,6 @@
             }
     };
 
-    private boolean isDialpadShowing() {
-        return mDialpadFragment != null && mDialpadFragment.isVisible();
-    }
-
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
@@ -426,7 +425,7 @@
     public void onClick(View view) {
         switch (view.getId()) {
             case R.id.floating_action_button:
-                if (!isDialpadShown) {
+                if (!mIsDialpadShown) {
                     mInCallDialpadUp = false;
                     showDialpadFragment(true);
                 } else {
@@ -497,7 +496,7 @@
     public boolean onLongClick(View view) {
         switch (view.getId()) {
             case R.id.floating_action_button:
-                if (isDialpadShown) {
+                if (mIsDialpadShown) {
                     // Dial button was pressed; tell the Dialpad fragment
                     mDialpadFragment.dialButtonPressed();
                     return true;  // Consume the event
@@ -528,34 +527,109 @@
         super.onActivityResult(requestCode, resultCode, data);
     }
 
+    /**
+     * Initiates a fragment transaction to show the dialpad fragment. Animations and other visual
+     * updates are handled by a callback which is invoked after the dialpad fragment is shown.
+     * @see #onDialpadShown
+     */
     private void showDialpadFragment(boolean animate) {
+        if (mIsDialpadShown) {
+            return;
+        }
+        mIsDialpadShown = true;
         mDialpadFragment.setAnimate(animate);
 
         final FragmentTransaction ft = getFragmentManager().beginTransaction();
-        if (animate) {
-            ft.setCustomAnimations(R.anim.slide_in, 0);
-        } else {
-            mDialpadFragment.setYFraction(0);
-        }
         ft.show(mDialpadFragment);
         ft.commit();
     }
 
+    /**
+     * Callback from child DialpadFragment when the dialpad is shown.
+     */
+    public void onDialpadShown() {
+        updateFloatingActionButton();
+        if (mDialpadFragment.getAnimate()) {
+            Animation slideIn = AnimationUtils.loadAnimation(this, R.anim.slide_in);
+            mDialpadFragment.getView().startAnimation(slideIn);
+        } else {
+            mDialpadFragment.setYFraction(0);
+        }
+
+        if (mListsFragment != null && mListsFragment.isResumed() && mListsFragment.isVisible()) {
+            // If the favorites fragment is showing, fade to blank.
+            mFragmentsFrame.animate().alpha(0.0f);
+            parentLayout.setBackgroundColor(mContactListBackgroundColor);
+        }
+
+        updateSearchFragmentPosition();
+        getActionBar().hide();
+    }
+
+    /**
+     * Initiates animations and other visual updates to hide the dialpad. The fragment is hidden in
+     * a callback after the hide animation ends.
+     * @see #commitDialpadFragmentHide
+     */
     public void hideDialpadFragment(boolean animate, boolean clearDialpad) {
-        if (mDialpadFragment == null) return;
+        if (mDialpadFragment == null) {
+            return;
+        }
         if (clearDialpad) {
             mDialpadFragment.clearDialpad();
         }
-        if (!mDialpadFragment.isVisible()) return;
-        mDialpadFragment.setAnimate(animate);
-        final FragmentTransaction ft = getFragmentManager().beginTransaction();
-        if (animate) {
-            ft.setCustomAnimations(0, R.anim.slide_out);
+        if (!mIsDialpadShown) {
+            return;
         }
+        mIsDialpadShown = false;
+        mDialpadFragment.setAnimate(animate);
+
+        updateFloatingActionButton();
+        if (animate) {
+            Animation slideOut = AnimationUtils.loadAnimation(this, R.anim.slide_out);
+            slideOut.setAnimationListener(new ActivityAnimationListener() {
+                @Override
+                public void onAnimationEnd(Animation animation) {
+                    commitDialpadFragmentHide();
+                }
+            });
+            mDialpadFragment.getView().startAnimation(slideOut);
+        } else {
+            commitDialpadFragmentHide();
+        }
+
+        if (mListsFragment != null && mListsFragment.isVisible()) {
+            mFragmentsFrame.animate().alpha(1.0f);
+            parentLayout.setBackgroundColor(mDialerBackgroundColor);
+        }
+
+        updateSearchFragmentPosition();
+        getActionBar().show();
+    }
+
+    /**
+     * Finishes hiding the dialpad fragment after any animations are completed.
+     */
+    private void commitDialpadFragmentHide() {
+        final FragmentTransaction ft = getFragmentManager().beginTransaction();
         ft.hide(mDialpadFragment);
         ft.commit();
     }
 
+    private void updateSearchFragmentPosition() {
+        int translationValue = mIsDialpadShown ?  -mActionBarHeight : 0;
+        SearchFragment fragment = null;
+        if (mInDialpadSearch) {
+            fragment = mSmartDialSearchFragment;
+        } else if (mInRegularSearch) {
+            fragment = mRegularSearchFragment;
+        }
+        if (fragment != null && fragment.isVisible()) {
+            fragment.getView().animate().translationY(translationValue)
+                    .setInterpolator(hideActionBarInterpolator).setDuration(ANIMATION_DURATION);
+        }
+    }
+
     private boolean getInSearchUi() {
         return mInDialpadSearch || mInRegularSearch;
     }
@@ -570,64 +644,6 @@
         hideDialpadFragment(false, true);
     }
 
-    /**
-     * Callback from child DialpadFragment when the dialpad is shown.
-     */
-    public void onDialpadShown() {
-        isDialpadShown = true;
-        mFloatingActionButton.setImageResource(R.drawable.fab_ic_call);
-        mFloatingActionButton.setContentDescription(
-                getResources().getString(R.string.description_dial_button));
-
-        SearchFragment fragment = null;
-        if (mInDialpadSearch) {
-            fragment = mSmartDialSearchFragment;
-        } else if (mInRegularSearch) {
-            fragment = mRegularSearchFragment;
-        }
-        if (fragment != null && fragment.isVisible()) {
-            fragment.getView().animate().translationY(-mActionBarHeight)
-                    .setInterpolator(hideActionBarInterpolator).setDuration(ANIMATION_DURATION);
-        }
-
-        if (mListsFragment != null && mListsFragment.isResumed() && mListsFragment.isVisible()) {
-            // If the favorites fragment is showing, fade to blank.
-            mFragmentsFrame.animate().alpha(0.0f);
-            parentLayout.setBackgroundColor(mContactListBackgroundColor);
-        }
-        getActionBar().hide();
-        alignFloatingActionButtonMiddle();
-    }
-
-    /**
-     * Callback from child DialpadFragment when the dialpad is hidden.
-     */
-    public void onDialpadHidden() {
-        isDialpadShown = false;
-        mFloatingActionButton.setImageResource(R.drawable.fab_ic_dial);
-        mFloatingActionButton.setContentDescription(
-                getResources().getString(R.string.action_menu_dialpad_button));
-
-        SearchFragment fragment = null;
-        if (mInDialpadSearch) {
-            fragment = mSmartDialSearchFragment;
-        } else if (mInRegularSearch) {
-            fragment = mRegularSearchFragment;
-        }
-        if (fragment != null && fragment.isVisible()) {
-            fragment.getView().animate().translationY(0)
-                    .setInterpolator(showActionBarInterpolator).setDuration(ANIMATION_DURATION);
-        }
-
-        if (mListsFragment != null && mListsFragment.isVisible()) {
-            mFragmentsFrame.animate().alpha(1.0f);
-            parentLayout.setBackgroundColor(mDialerBackgroundColor);
-
-        }
-        getActionBar().show();
-        alignFloatingActionButtonByTab(mCurrentTabPosition);
-    }
-
     private void hideInputMethod(View view) {
         final InputMethodManager imm = (InputMethodManager) getSystemService(
                 Context.INPUT_METHOD_SERVICE);
@@ -805,7 +821,7 @@
         getFragmentManager().popBackStack(0, FragmentManager.POP_BACK_STACK_INCLUSIVE);
         setNotInSearchUi();
 
-        if (isDialpadShowing()) {
+        if (mIsDialpadShown) {
             mFragmentsFrame.setAlpha(0);
         }
     }
@@ -820,7 +836,7 @@
 
     @Override
     public void onBackPressed() {
-        if (mDialpadFragment != null && mDialpadFragment.isVisible()) {
+        if (mIsDialpadShown) {
             hideDialpadFragment(true, false);
         } else if (getInSearchUi()) {
             mSearchView.setText(null);
@@ -980,7 +996,7 @@
     public void onPageSelected(int position) {
         mCurrentTabPosition = position;
         // If the dialpad is showing, the floating action button should always be middle aligned.
-        if (!isDialpadShowing()) {
+        if (!mIsDialpadShown) {
             alignFloatingActionButtonByTab(mCurrentTabPosition);
         }
     }
@@ -989,6 +1005,20 @@
     public void onPageScrollStateChanged(int state) {
     }
 
+    private void updateFloatingActionButton() {
+        if (mIsDialpadShown) {
+            mFloatingActionButton.setImageResource(R.drawable.fab_ic_call);
+            mFloatingActionButton.setContentDescription(
+                    getResources().getString(R.string.description_dial_button));
+            alignFloatingActionButtonByTab(mCurrentTabPosition);
+        } else {
+            mFloatingActionButton.setImageResource(R.drawable.fab_ic_dial);
+            mFloatingActionButton.setContentDescription(
+                    getResources().getString(R.string.action_menu_dialpad_button));
+            alignFloatingActionButtonMiddle();
+        }
+    }
+
     private void alignFloatingActionButtonByTab(int position) {
         if (position == ListsFragment.TAB_INDEX_SPEED_DIAL) {
             alignFloatingActionButtonMiddle();
@@ -1012,4 +1042,21 @@
         params.addRule(RelativeLayout.CENTER_HORIZONTAL);
         mFloatingActionButtonContainer.setLayoutParams(params);
     }
+
+    /**
+     * Convenience class which implements AnimationListener interface as null-op methods.
+     */
+    private class ActivityAnimationListener implements AnimationListener {
+        @Override
+        public void onAnimationStart(Animation animation) {
+        }
+
+        @Override
+        public void onAnimationEnd(Animation animation) {
+        }
+
+        @Override
+        public void onAnimationRepeat(Animation animation) {
+        }
+    }
 }
diff --git a/src/com/android/dialer/dialpad/DialpadFragment.java b/src/com/android/dialer/dialpad/DialpadFragment.java
index 4557bd4..418d54a 100644
--- a/src/com/android/dialer/dialpad/DialpadFragment.java
+++ b/src/com/android/dialer/dialpad/DialpadFragment.java
@@ -347,29 +347,6 @@
                 false);
         fragmentView.buildLayer();
 
-        final ViewTreeObserver vto = fragmentView.getViewTreeObserver();
-        // Adjust the translation of the DialpadFragment in a preDrawListener instead of in
-        // DialtactsActivity, because at the point in time when the DialpadFragment is added,
-        // its views have not been laid out yet.
-        final OnPreDrawListener preDrawListener = new OnPreDrawListener() {
-
-            @Override
-            public boolean onPreDraw() {
-
-                if (isHidden()) return true;
-                if (mAnimate && fragmentView.getTranslationY() == 0) {
-                    ((DialpadSlidingLinearLayout) fragmentView).setYFraction(
-                            DIALPAD_SLIDE_FRACTION);
-                }
-                final ViewTreeObserver vto = fragmentView.getViewTreeObserver();
-                vto.removeOnPreDrawListener(this);
-                return true;
-            }
-
-        };
-
-        vto.addOnPreDrawListener(preDrawListener);
-
         Resources r = getResources();
 
         mDialpadView = (DialpadView) fragmentView.findViewById(R.id.dialpad_view);
@@ -1593,9 +1570,7 @@
         final DialtactsActivity activity = (DialtactsActivity) getActivity();
         final DialpadView dialpadView = (DialpadView) getView().findViewById(R.id.dialpad_view);
         if (activity == null) return;
-        if (hidden) {
-            activity.onDialpadHidden();
-        } else {
+        if (!hidden) {
             if (mAnimate) {
                 dialpadView.animateShow();
             }
@@ -1608,6 +1583,10 @@
         mAnimate = value;
     }
 
+    public boolean getAnimate() {
+        return mAnimate;
+    }
+
     public void setYFraction(float yFraction) {
         ((DialpadSlidingLinearLayout) getView()).setYFraction(yFraction);
     }