am 47612e5f: am 8c92be0f: am d462d3a9: Scroll to top of raw_contact on expansion

* commit '47612e5f4b04dcf5f1b27654f93aa4247094453a':
  Scroll to top of raw_contact on expansion
diff --git a/src/com/android/contacts/editor/BaseRawContactEditorView.java b/src/com/android/contacts/editor/BaseRawContactEditorView.java
index 473f2ab..01742bb 100644
--- a/src/com/android/contacts/editor/BaseRawContactEditorView.java
+++ b/src/com/android/contacts/editor/BaseRawContactEditorView.java
@@ -153,6 +153,14 @@
                     if (!isCollapsed) {
                         EditorAnimator.getInstance().slideAndFadeIn(mCollapsibleSection,
                                 startingHeight);
+                        // We want to place the focus near the top of the screen now that a
+                        // potentially focused editor is being collapsed.
+                        EditorAnimator.placeFocusAtTopOfScreenAfterReLayout(mCollapsibleSection);
+                    } else {
+                        // When expanding we should scroll the expanded view onto the screen.
+                        // Otherwise, user's may not notice that any expansion happened.
+                        EditorAnimator.getInstance().scrollViewToTop(mAccountHeaderContainer);
+                        mCollapsibleSection.requestFocus();
                     }
                     if (mListener != null) {
                         mListener.onEditorExpansionChanged();
diff --git a/src/com/android/contacts/editor/EditorAnimator.java b/src/com/android/contacts/editor/EditorAnimator.java
index 35ed1de..2e17e23 100644
--- a/src/com/android/contacts/editor/EditorAnimator.java
+++ b/src/com/android/contacts/editor/EditorAnimator.java
@@ -25,6 +25,7 @@
 import android.view.ViewGroup;
 import android.view.ViewParent;
 import android.widget.LinearLayout;
+import android.widget.ScrollView;
 
 import com.android.contacts.util.SchedulingUtils;
 import com.google.common.collect.Lists;
@@ -145,6 +146,57 @@
     }
 
     /**
+     * Smoothly scroll {@param targetView}'s parent ScrollView to the top of {@param targetView}.
+     */
+    public void scrollViewToTop(final View targetView) {
+        final ScrollView scrollView = getParentScrollView(targetView);
+        SchedulingUtils.doAfterLayout(scrollView, new Runnable() {
+            @Override
+            public void run() {
+                ScrollView scrollView = getParentScrollView(targetView);
+                scrollView.smoothScrollTo(0, offsetFromTopOfViewGroup(targetView, scrollView)
+                        + scrollView.getScrollY());
+            }
+        });
+        // Clear the focused element so it doesn't interfere with scrolling.
+        View view = scrollView.findFocus();
+        if (view != null) {
+            view.clearFocus();
+        }
+    }
+
+    public static void placeFocusAtTopOfScreenAfterReLayout(final View view) {
+        // In order for the focus to be placed at the top of the Window, we need
+        // to wait for layout. Otherwise we don't know where the top of the screen is.
+        SchedulingUtils.doAfterLayout(view, new Runnable() {
+            @Override
+            public void run() {
+                EditorAnimator.getParentScrollView(view).clearFocus();
+            }
+        });
+    }
+
+    private int offsetFromTopOfViewGroup(View view, ViewGroup viewGroup) {
+        int viewLocation[] = new int[2];
+        int viewGroupLocation[] = new int[2];
+        viewGroup.getLocationOnScreen(viewGroupLocation);
+        view.getLocationOnScreen(viewLocation);
+        return viewLocation[1] - viewGroupLocation[1];
+    }
+
+    private static ScrollView getParentScrollView(View view) {
+        while (true) {
+            ViewParent parent = view.getParent();
+            if (parent instanceof ScrollView)
+                return (ScrollView) parent;
+            if (!(parent instanceof View))
+                throw new IllegalArgumentException(
+                        "The editor should be contained inside a ScrollView.");
+            view = (View) parent;
+        }
+    }
+
+    /**
      * Creates a translation-animation for the given views
      */
     private static void translateViews(List<Animator> animators, List<View> views, float fromY,