Changing layout and behavior of aggregation suggestions.

Bug: 3098963

Change-Id: I50c8d56bf97b1af15200ce416afc6810899f16d7
diff --git a/res/layout-xlarge/aggregation_suggestions.xml b/res/layout-xlarge/aggregation_suggestions.xml
index 81b4edd..3a314b6 100644
--- a/res/layout-xlarge/aggregation_suggestions.xml
+++ b/res/layout-xlarge/aggregation_suggestions.xml
@@ -17,39 +17,16 @@
  */
 -->
 
-<com.android.contacts.widget.InterpolatingLayout
+<LinearLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:ex="http://schemas.android.com/apk/res/com.android.contacts"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
-    android:paddingBottom="20dip">
-
+    android:orientation="vertical"
+    android:background="@drawable/aggregation_suggestions_bg_light_holo"
+    android:paddingBottom="10dip">
     <LinearLayout
-        android:layout_width="wrap_content"
+        android:id="@+id/aggregation_suggestions"
+        android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:orientation="vertical"
-        android:background="@drawable/aggregation_suggestions_bg_light_holo"
-        android:minWidth="100dip"
-        android:paddingBottom="10dip"
-        ex:layout_narrowParentWidth="600dip"
-        ex:layout_narrowWidth="400dip"
-        ex:layout_wideParentWidth="300dip"
-        ex:layout_wideWidth="240dip">
-        <TextView
-            android:id="@+id/aggregation_suggestion_title"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layout_alignParentTop="true"
-            android:layout_alignParentLeft="true"
-            android:layout_marginLeft="5dip"
-            android:textAppearance="?android:attr/textAppearanceMedium"
-            android:textColor="?android:attr/textColorTertiary"
-            android:textStyle="bold" />
-
-        <LinearLayout
-            android:id="@+id/aggregation_suggestions"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:orientation="vertical" />
-    </LinearLayout>
-</com.android.contacts.widget.InterpolatingLayout>
\ No newline at end of file
+        android:orientation="vertical" />
+</LinearLayout>
diff --git a/res/layout-xlarge/aggregation_suggestions_item.xml b/res/layout-xlarge/aggregation_suggestions_item.xml
index 865c492..642b865 100644
--- a/res/layout-xlarge/aggregation_suggestions_item.xml
+++ b/res/layout-xlarge/aggregation_suggestions_item.xml
@@ -25,24 +25,6 @@
     android:paddingLeft="5dip"
     android:paddingRight="15dip"
 >
-    <Button
-        android:id="@+id/aggregation_suggestion_join_button"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:text="@string/aggregation_suggestion_join_button"
-        android:layout_centerInParent="true"
-        android:layout_alignParentRight="true"
-    />
-
-    <Button
-        android:id="@+id/aggregation_suggestion_edit_button"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:text="@string/aggregation_suggestion_edit_button"
-        android:layout_centerInParent="true"
-        android:layout_alignParentRight="true"
-    />
-
     <ImageView
         android:id="@+id/aggregation_suggestion_photo"
         android:layout_width="@dimen/aggregation_suggestion_icon_size"
@@ -58,10 +40,9 @@
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_toRightOf="@id/aggregation_suggestion_photo"
-        android:layout_toLeftOf="@id/aggregation_suggestion_join_button"
         android:layout_marginLeft="10dip"
         android:layout_marginTop="4dip"
-        android:textAppearance="?android:attr/textAppearanceMedium"
+        android:textAppearance="?android:attr/textAppearanceLarge"
         android:textColor="?android:attr/textColorSecondary"
     />
 
@@ -70,7 +51,6 @@
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_toRightOf="@id/aggregation_suggestion_photo"
-        android:layout_toLeftOf="@id/aggregation_suggestion_join_button"
         android:layout_below="@id/aggregation_suggestion_name"
         android:layout_marginLeft="10dip"
         android:textAppearance="?android:attr/textAppearanceMedium"
diff --git a/res/layout/aggregation_suggestions.xml b/res/layout/aggregation_suggestions.xml
index 0542daa..3b9d278 100644
--- a/res/layout/aggregation_suggestions.xml
+++ b/res/layout/aggregation_suggestions.xml
@@ -22,18 +22,6 @@
     android:layout_height="wrap_content"
     android:orientation="vertical"
     android:background="@drawable/aggregation_suggestions_bg">
-    <TextView
-        android:id="@+id/aggregation_suggestion_title"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_alignParentTop="true"
-        android:layout_alignParentLeft="true"
-        android:layout_marginLeft="5dip"
-        android:textAppearance="?android:attr/textAppearanceMedium"
-        android:textColor="?android:attr/textColorPrimary"
-        android:textStyle="bold"
-    />
-
     <LinearLayout
         android:id="@+id/aggregation_suggestions"
         android:layout_width="match_parent"
diff --git a/res/layout/aggregation_suggestions_item.xml b/res/layout/aggregation_suggestions_item.xml
index 988508b..cd27e2b 100644
--- a/res/layout/aggregation_suggestions_item.xml
+++ b/res/layout/aggregation_suggestions_item.xml
@@ -25,23 +25,6 @@
     android:paddingLeft="5dip"
     android:paddingRight="15dip"
 >
-    <Button
-        android:id="@+id/aggregation_suggestion_join_button"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:text="@string/aggregation_suggestion_join_button"
-        android:layout_centerInParent="true"
-        android:layout_alignParentRight="true"
-    />
-
-    <Button
-        android:id="@+id/aggregation_suggestion_edit_button"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:text="@string/aggregation_suggestion_edit_button"
-        android:layout_centerInParent="true"
-        android:layout_alignParentRight="true"
-    />
 
     <ImageView
         android:id="@+id/aggregation_suggestion_photo"
@@ -58,7 +41,6 @@
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_toRightOf="@id/aggregation_suggestion_photo"
-        android:layout_toLeftOf="@id/aggregation_suggestion_join_button"
         android:layout_marginLeft="10dip"
         android:layout_marginTop="4dip"
         android:textAppearance="?android:attr/textAppearanceSmall"
@@ -70,7 +52,6 @@
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_toRightOf="@id/aggregation_suggestion_photo"
-        android:layout_toLeftOf="@id/aggregation_suggestion_join_button"
         android:layout_below="@id/aggregation_suggestion_name"
         android:layout_marginLeft="10dip"
         android:textAppearance="?android:attr/textAppearanceSmall"
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 49a4186..84f1db1 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1303,19 +1303,23 @@
     <!-- The name of the invisible local contact directory -->
     <string name="local_invisible_directory">Other</string>
 
-    <!-- The heading of the contact aggregation suggestions section in Contact editor. [CHAR LIMIT=128]-->
-    <plurals name="aggregation_suggestion_title">
-        <item quantity="one">Similar contact</item>
-        <item quantity="other">Similar contacts</item>
-    </plurals>
+    <!-- The title of a confirmation dialog shown when the user selects a
+        contact aggregation suggestion in Contact editor. [CHAR LIMIT=128]-->
+    <string name="aggregation_suggestion_join_dialog_title">Join contacts</string>
 
-    <!-- The heading of the aggregation suggestion section of the Contact editor
-        indicating the contact that will be joined with the current contact. [CHAR LIMIT=128]-->
-    <string name="aggregation_suggestion_joined_title">Joined contact:</string>
+    <!-- The message in a confirmation dialog shown when the user selects a
+        contact aggregation suggestion in Contact editor. [CHAR LIMIT=512]-->
+    <string name="aggregation_suggestion_join_dialog_message">Join
+        the current contact with the selected contact?</string>
 
-    <!-- The button next to a contact aggregation suggestion in Contact editor. Causes a logical
-      join with the suggested contact. [CHAR LIMIT=12]-->
-    <string name="aggregation_suggestion_join_button">Join</string>
+    <!-- The title of a confirmation dialog shown when the user selects a
+        contact aggregation suggestion in Contact editor. [CHAR LIMIT=128]-->
+    <string name="aggregation_suggestion_edit_dialog_title">Edit selected contacts</string>
+
+    <!-- The message in a confirmation dialog shown when the user selects a 
+        contact aggregation suggestion in Contact editor. [CHAR LIMIT=512]-->
+    <string name="aggregation_suggestion_edit_dialog_message">Switch to editing
+        the selected contact? Information you entered so far will be copied.</string>
 
     <!-- The button next to a contact aggregation suggestion in Contact editor. Causes the UI
     to switch to the suggested contact in the editor. [CHAR LIMIT=12]-->
diff --git a/src/com/android/contacts/model/EntityDeltaList.java b/src/com/android/contacts/model/EntityDeltaList.java
index 455cced..a998a37 100644
--- a/src/com/android/contacts/model/EntityDeltaList.java
+++ b/src/com/android/contacts/model/EntityDeltaList.java
@@ -43,7 +43,7 @@
  */
 public class EntityDeltaList extends ArrayList<EntityDelta> implements Parcelable {
     private boolean mSplitRawContacts;
-    private List<Long> mJoinWithRawContactIds;
+    private long[] mJoinWithRawContactIds;
 
     private EntityDeltaList() {
     }
@@ -340,7 +340,7 @@
         mSplitRawContacts = true;
     }
 
-    public void setJoinWithRawContacts(List<Long> rawContactIds) {
+    public void setJoinWithRawContacts(long[] rawContactIds) {
         mJoinWithRawContactIds = rawContactIds;
     }
 
@@ -357,7 +357,7 @@
         for (EntityDelta delta : this) {
             dest.writeParcelable(delta, flags);
         }
-        dest.writeList(mJoinWithRawContactIds);
+        dest.writeLongArray(mJoinWithRawContactIds);
     }
 
     @SuppressWarnings("unchecked")
@@ -367,7 +367,7 @@
         for (int i = 0; i < size; i++) {
             this.add(source.<EntityDelta> readParcelable(loader));
         }
-        mJoinWithRawContactIds = source.readArrayList(loader);
+        mJoinWithRawContactIds = source.createLongArray();
     }
 
     public static final Parcelable.Creator<EntityDeltaList> CREATOR =
diff --git a/src/com/android/contacts/views/editor/AggregationSuggestionView.java b/src/com/android/contacts/views/editor/AggregationSuggestionView.java
index 8c8adf7..0c35a39 100644
--- a/src/com/android/contacts/views/editor/AggregationSuggestionView.java
+++ b/src/com/android/contacts/views/editor/AggregationSuggestionView.java
@@ -17,21 +17,17 @@
 package com.android.contacts.views.editor;
 
 import com.android.contacts.R;
-import com.android.contacts.model.BaseAccountType;
 import com.android.contacts.model.AccountTypes;
+import com.android.contacts.model.BaseAccountType;
 import com.android.contacts.views.editor.AggregationSuggestionEngine.RawContact;
 import com.android.contacts.views.editor.AggregationSuggestionEngine.Suggestion;
 import com.google.android.collect.Lists;
 
-import android.content.ContentUris;
 import android.content.Context;
 import android.graphics.BitmapFactory;
 import android.net.Uri;
 import android.provider.ContactsContract.Contacts;
 import android.util.AttributeSet;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.widget.Button;
 import android.widget.ImageView;
 import android.widget.RelativeLayout;
 import android.widget.TextView;
@@ -42,7 +38,7 @@
 /**
  * A view that contains a name, picture and other data for a contact aggregation suggestion.
  */
-public class AggregationSuggestionView extends RelativeLayout implements OnClickListener {
+public class AggregationSuggestionView extends RelativeLayout {
 
     public interface Listener {
 
@@ -67,14 +63,17 @@
 
     public AggregationSuggestionView(Context context) {
         super(context);
+        setClickable(true);
     }
 
     public AggregationSuggestionView(Context context, AttributeSet attrs) {
         super(context, attrs);
+        setClickable(true);
     }
 
     public AggregationSuggestionView(Context context, AttributeSet attrs, int defStyle) {
         super(context, attrs, defStyle);
+        setClickable(true);
     }
 
     public void setNewContact(boolean flag) {
@@ -106,15 +105,6 @@
             dataText = suggestion.phoneNumber;
         }
         data.setText(dataText);
-
-        boolean canEdit = canEditSuggestedContact();
-        Button join = (Button) findViewById(R.id.aggregation_suggestion_join_button);
-        join.setOnClickListener(this);
-        join.setVisibility(canEdit ? View.GONE : View.VISIBLE);
-
-        Button edit = (Button) findViewById(R.id.aggregation_suggestion_edit_button);
-        edit.setOnClickListener(this);
-        edit.setVisibility(canEdit ? View.VISIBLE : View.GONE);
     }
 
     /**
@@ -146,17 +136,19 @@
     }
 
     @Override
-    public void onClick(View v) {
+    public boolean performClick() {
         if (mListener != null) {
-            if (v.getId() == R.id.aggregation_suggestion_join_button) {
+            if (canEditSuggestedContact()) {
+                mListener.onEditAction(Contacts.getLookupUri(mContactId, mLookupKey));
+            } else {
                 ArrayList<Long> rawContactIds = Lists.newArrayList();
                 for (RawContact rawContact : mRawContacts) {
                     rawContactIds.add(rawContact.rawContactId);
                 }
                 mListener.onJoinAction(mContactId, rawContactIds);
-            } else {
-                mListener.onEditAction(Contacts.getLookupUri(mContactId, mLookupKey));
             }
+            return true;
         }
+        return false;
     }
 }
diff --git a/src/com/android/contacts/views/editor/ContactEditorFragment.java b/src/com/android/contacts/views/editor/ContactEditorFragment.java
index 6b24f3a..b7c35c0 100644
--- a/src/com/android/contacts/views/editor/ContactEditorFragment.java
+++ b/src/com/android/contacts/views/editor/ContactEditorFragment.java
@@ -34,6 +34,9 @@
 
 import android.accounts.Account;
 import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.DialogFragment;
 import android.app.Fragment;
 import android.app.LoaderManager;
 import android.app.LoaderManager.LoaderCallbacks;
@@ -47,6 +50,7 @@
 import android.content.ContentValues;
 import android.content.Context;
 import android.content.CursorLoader;
+import android.content.DialogInterface;
 import android.content.Entity;
 import android.content.Intent;
 import android.content.Loader;
@@ -78,9 +82,9 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.ViewGroup.LayoutParams;
+import android.view.ViewGroup.MarginLayoutParams;
 import android.view.ViewStub;
 import android.widget.LinearLayout;
-import android.widget.TextView;
 import android.widget.Toast;
 
 import java.io.File;
@@ -94,7 +98,8 @@
 
 public class ContactEditorFragment extends Fragment implements
         SplitContactConfirmationDialogFragment.Listener, PhotoDialogFragment.Listener,
-        SelectAccountDialogFragment.Listener, AggregationSuggestionEngine.Listener {
+        SelectAccountDialogFragment.Listener, AggregationSuggestionEngine.Listener,
+        AggregationSuggestionView.Listener {
 
     private static final String TAG = "ContactEditorFragment";
 
@@ -1177,7 +1182,8 @@
 
     @Override
     public void onAggregationSuggestionChange() {
-        View rawContactView = getContactEditorView(mAggregationSuggestionsRawContactId);
+        RawContactEditorView rawContactView =
+                (RawContactEditorView)getRawContactEditorView(mAggregationSuggestionsRawContactId);
         if (rawContactView == null) {
             return;
         }
@@ -1199,11 +1205,6 @@
 
         List<Suggestion> suggestions = mAggregationSuggestionEngine.getSuggestions();
 
-        TextView title = (TextView) mAggregationSuggestionView.findViewById(
-                R.id.aggregation_suggestion_title);
-        title.setText(getActivity().getResources().getQuantityString(
-                R.plurals.aggregation_suggestion_title, count));
-
         LinearLayout itemList = (LinearLayout) mAggregationSuggestionView.findViewById(
                 R.id.aggregation_suggestions);
         itemList.removeAllViews();
@@ -1218,30 +1219,12 @@
                     new LinearLayout.LayoutParams(
                             LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
             suggestionView.setNewContact(mState.size() == 1 && mState.get(0).isContactInsert());
-            suggestionView.setListener(new AggregationSuggestionView.Listener() {
-
-                @Override
-                public void onJoinAction(long contactId, List<Long> rawContactIds) {
-                    mState.setJoinWithRawContacts(rawContactIds);
-                    // If we are in the edit mode (indicated by a non-zero contact ID),
-                    // join the suggested contact, save all changes, and stay in the editor.
-                    doSaveAction(SaveMode.RELOAD);
-                }
-
-                @Override
-                public void onEditAction(Uri contactLookupUri) {
-                    // Abandon the currently edited contact and switch to editing
-                    // the suggested one, transferring all the data there
-                    if (mListener != null) {
-                        mListener.onEditOtherContactRequested(
-                                contactLookupUri, mState.get(0).getContentValues());
-                    }
-                }
-            });
+            suggestionView.setListener(this);
             suggestionView.bindSuggestion(suggestion);
             itemList.addView(suggestionView);
         }
 
+        adjustAggregationSuggestionViewLayout(rawContactView);
         mAggregationSuggestionView.setVisibility(View.VISIBLE);
 
         if (requestOnScreen) {
@@ -1256,6 +1239,115 @@
     }
 
     /**
+     * Adjusts the layout of the aggregation suggestion view so that it is placed directly
+     * underneath and have the same width as the last text editor of the contact name editor.
+     */
+    private void adjustAggregationSuggestionViewLayout(RawContactEditorView rawContactView) {
+        FieldEditorView nameEditor = rawContactView.getNameEditor();
+        Rect rect = new Rect();
+        nameEditor.acquireEditorBounds(rect);
+        MarginLayoutParams layoutParams =
+                (MarginLayoutParams) mAggregationSuggestionView.getLayoutParams();
+        layoutParams.leftMargin = rect.left;
+        layoutParams.width = rect.width();
+        mAggregationSuggestionView.setLayoutParams(layoutParams);
+    }
+
+    @Override
+    public void onJoinAction(long contactId, List<Long> rawContactIdList) {
+        long rawContactIds[] = new long[rawContactIdList.size()];
+        for (int i = 0; i < rawContactIds.length; i++) {
+            rawContactIds[i] = rawContactIdList.get(i);
+        }
+        JoinSuggestedContactDialogFragment dialog =
+                new JoinSuggestedContactDialogFragment();
+        Bundle args = new Bundle();
+        args.putLongArray("rawContactIds", rawContactIds);
+        dialog.setArguments(args);
+        dialog.setTargetFragment(this, 0);
+        dialog.show(getFragmentManager(), "join");
+    }
+
+    public static class JoinSuggestedContactDialogFragment extends DialogFragment {
+
+        @Override
+        public Dialog onCreateDialog(Bundle savedInstanceState) {
+            return new AlertDialog.Builder(getActivity())
+                    .setIcon(android.R.drawable.ic_dialog_alert)
+                    .setTitle(R.string.aggregation_suggestion_join_dialog_title)
+                    .setMessage(R.string.aggregation_suggestion_join_dialog_message)
+                    .setPositiveButton(android.R.string.yes,
+                        new DialogInterface.OnClickListener() {
+                            public void onClick(DialogInterface dialog, int whichButton) {
+                                ContactEditorFragment targetFragment =
+                                        (ContactEditorFragment) getTargetFragment();
+                                long rawContactIds[] =
+                                        getArguments().getLongArray("rawContactIds");
+                                targetFragment.doJoinSuggestedContact(rawContactIds);
+                            }
+                        }
+                    )
+                    .setNegativeButton(android.R.string.no, null)
+                    .create();
+        }
+    }
+
+    /**
+     * Joins the suggested contact (specified by the id's of constituent raw
+     * contacts), save all changes, and stay in the editor.
+     */
+    protected void doJoinSuggestedContact(long[] rawContactIds) {
+        mState.setJoinWithRawContacts(rawContactIds);
+        doSaveAction(SaveMode.RELOAD);
+    }
+
+    @Override
+    public void onEditAction(Uri contactLookupUri) {
+        SuggestionEditConfirmationDialogFragment dialog =
+                new SuggestionEditConfirmationDialogFragment();
+        Bundle args = new Bundle();
+        args.putParcelable("contactUri", contactLookupUri);
+        dialog.setArguments(args);
+        dialog.setTargetFragment(this, 0);
+        dialog.show(getFragmentManager(), "edit");
+    }
+
+    public static class SuggestionEditConfirmationDialogFragment extends DialogFragment {
+
+        @Override
+        public Dialog onCreateDialog(Bundle savedInstanceState) {
+            return new AlertDialog.Builder(getActivity())
+                    .setIcon(android.R.drawable.ic_dialog_alert)
+                    .setTitle(R.string.aggregation_suggestion_edit_dialog_title)
+                    .setMessage(R.string.aggregation_suggestion_edit_dialog_message)
+                    .setPositiveButton(android.R.string.yes,
+                        new DialogInterface.OnClickListener() {
+                            public void onClick(DialogInterface dialog, int whichButton) {
+                                ContactEditorFragment targetFragment =
+                                        (ContactEditorFragment) getTargetFragment();
+                                Uri contactUri =
+                                        getArguments().getParcelable("contactUri");
+                                targetFragment.doEditSuggestedContact(contactUri);
+                            }
+                        }
+                    )
+                    .setNegativeButton(android.R.string.no, null)
+                    .create();
+        }
+    }
+
+    /**
+     * Abandons the currently edited contact and switches to editing the suggested
+     * one, transferring all the data there
+     */
+    protected void doEditSuggestedContact(Uri contactUri) {
+        if (mListener != null) {
+            mListener.onEditOtherContactRequested(
+                    contactUri, mState.get(0).getContentValues());
+        }
+    }
+
+    /**
      * Scrolls the editor if necessary to reveal the aggregation suggestion that is
      * shown below the name editor. Makes sure that the currently focused field
      * remains visible.
@@ -1480,7 +1572,7 @@
      * Sets the photo stored in mPhoto and writes it to the RawContact with the given id
      */
     private void setPhoto(long rawContact, Bitmap photo) {
-        BaseRawContactEditorView requestingEditor = getContactEditorView(rawContact);
+        BaseRawContactEditorView requestingEditor = getRawContactEditorView(rawContact);
         if (requestingEditor != null) {
             requestingEditor.setPhotoBitmap(photo);
         } else {
@@ -1491,7 +1583,7 @@
     /**
      * Finds raw contact editor view for the given rawContactId.
      */
-    public BaseRawContactEditorView getContactEditorView(long rawContactId) {
+    public BaseRawContactEditorView getRawContactEditorView(long rawContactId) {
         for (int i = 0; i < mContent.getChildCount(); i++) {
             final View childView = mContent.getChildAt(i);
             if (childView instanceof BaseRawContactEditorView) {
diff --git a/src/com/android/contacts/views/editor/FieldEditorView.java b/src/com/android/contacts/views/editor/FieldEditorView.java
index 926782d..c16c7ed 100644
--- a/src/com/android/contacts/views/editor/FieldEditorView.java
+++ b/src/com/android/contacts/views/editor/FieldEditorView.java
@@ -33,6 +33,7 @@
 import android.content.DialogInterface;
 import android.content.Entity;
 import android.content.res.Resources;
+import android.graphics.Rect;
 import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -685,4 +686,20 @@
                 mFieldEditTexts[0].requestFocus();
         }
     }
+
+    /**
+     * Populates the bound rectangle with the bounds of the last editor field inside this view.
+     */
+    public void acquireEditorBounds(Rect bounds) {
+        if (mFieldEditTexts != null) {
+            for (int i = mFieldEditTexts.length; --i >= 0;) {
+                EditText editText = mFieldEditTexts[i];
+                if (editText.getVisibility() == View.VISIBLE) {
+                    bounds.set(editText.getLeft(), editText.getTop(), editText.getRight(),
+                            editText.getBottom());
+                    return;
+                }
+            }
+        }
+    }
 }