Commit ee7d152c authored by estade@chromium.org's avatar estade@chromium.org

android: Don't allow AutofillPopup on outside touch

By default, PopupWindows dismiss when the user touches outside the window. The only
way to avert this behavior when using a ListPopupWindow is to rely on a hidden API.

This manifested as the linked bug because each tap dismissed the popup and detached it from the anchor view. C++ didn't realize the popup was dismissed, and tried to update it, but there was no anchor view.

BUG=400601

Review URL: https://codereview.chromium.org/442933002

Cr-Commit-Position: refs/heads/master@{#291463}
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@291463 0039d316-1c4b-4281-b951-d872f2087c98
parent d0e4ad0c
...@@ -50,7 +50,7 @@ public class AwAutofillClient { ...@@ -50,7 +50,7 @@ public class AwAutofillClient {
mContentViewCore.getViewAndroidDelegate(), mContentViewCore.getViewAndroidDelegate(),
new AutofillPopup.AutofillPopupDelegate() { new AutofillPopup.AutofillPopupDelegate() {
@Override @Override
public void requestHide() { } public void dismissed() { }
@Override @Override
public void suggestionSelected(int listIndex) { public void suggestionSelected(int listIndex) {
nativeSuggestionSelected(mNativeAwAutofillClient, listIndex); nativeSuggestionSelected(mNativeAwAutofillClient, listIndex);
......
...@@ -35,7 +35,7 @@ public class AutofillPopupBridge implements AutofillPopupDelegate{ ...@@ -35,7 +35,7 @@ public class AutofillPopupBridge implements AutofillPopupDelegate{
new Handler().post(new Runnable() { new Handler().post(new Runnable() {
@Override @Override
public void run() { public void run() {
requestHide(); dismissed();
} }
}); });
} else { } else {
...@@ -51,8 +51,8 @@ public class AutofillPopupBridge implements AutofillPopupDelegate{ ...@@ -51,8 +51,8 @@ public class AutofillPopupBridge implements AutofillPopupDelegate{
} }
@Override @Override
public void requestHide() { public void dismissed() {
nativeRequestHide(mNativeAutofillPopup); nativePopupDismissed(mNativeAutofillPopup);
} }
@Override @Override
...@@ -109,7 +109,7 @@ public class AutofillPopupBridge implements AutofillPopupDelegate{ ...@@ -109,7 +109,7 @@ public class AutofillPopupBridge implements AutofillPopupDelegate{
array[index] = new AutofillSuggestion(label, sublabel, uniqueId); array[index] = new AutofillSuggestion(label, sublabel, uniqueId);
} }
private native void nativeRequestHide(long nativeAutofillPopupViewAndroid); private native void nativePopupDismissed(long nativeAutofillPopupViewAndroid);
private native void nativeSuggestionSelected(long nativeAutofillPopupViewAndroid, private native void nativeSuggestionSelected(long nativeAutofillPopupViewAndroid,
int listIndex); int listIndex);
} }
...@@ -82,7 +82,7 @@ public class AutofillTest extends ChromeShellTestBase { ...@@ -82,7 +82,7 @@ public class AutofillTest extends ChromeShellTestBase {
} }
@Override @Override
public void requestHide() { public void dismissed() {
} }
} }
......
...@@ -38,9 +38,9 @@ void AutofillPopupViewAndroid::Show() { ...@@ -38,9 +38,9 @@ void AutofillPopupViewAndroid::Show() {
} }
void AutofillPopupViewAndroid::Hide() { void AutofillPopupViewAndroid::Hide() {
controller_ = NULL;
JNIEnv* env = base::android::AttachCurrentThread(); JNIEnv* env = base::android::AttachCurrentThread();
Java_AutofillPopupBridge_hide(env, java_object_.obj()); Java_AutofillPopupBridge_hide(env, java_object_.obj());
delete this;
} }
void AutofillPopupViewAndroid::UpdateBoundsAndRedrawPopup() { void AutofillPopupViewAndroid::UpdateBoundsAndRedrawPopup() {
...@@ -84,8 +84,11 @@ void AutofillPopupViewAndroid::SuggestionSelected(JNIEnv* env, ...@@ -84,8 +84,11 @@ void AutofillPopupViewAndroid::SuggestionSelected(JNIEnv* env,
controller_->AcceptSuggestion(list_index); controller_->AcceptSuggestion(list_index);
} }
void AutofillPopupViewAndroid::RequestHide(JNIEnv* env, jobject obj) { void AutofillPopupViewAndroid::PopupDismissed(JNIEnv* env, jobject obj) {
controller_->Hide(); if (controller_)
controller_->ViewDestroyed();
delete this;
} }
void AutofillPopupViewAndroid::InvalidateRow(size_t) {} void AutofillPopupViewAndroid::InvalidateRow(size_t) {}
......
...@@ -29,7 +29,7 @@ class AutofillPopupViewAndroid : public AutofillPopupView { ...@@ -29,7 +29,7 @@ class AutofillPopupViewAndroid : public AutofillPopupView {
// Called when an autofill item was selected. // Called when an autofill item was selected.
void SuggestionSelected(JNIEnv* env, jobject obj, jint list_index); void SuggestionSelected(JNIEnv* env, jobject obj, jint list_index);
void RequestHide(JNIEnv* env, jobject obj); void PopupDismissed(JNIEnv* env, jobject obj);
static bool RegisterAutofillPopupViewAndroid(JNIEnv* env); static bool RegisterAutofillPopupViewAndroid(JNIEnv* env);
......
...@@ -6,8 +6,11 @@ package org.chromium.ui.autofill; ...@@ -6,8 +6,11 @@ package org.chromium.ui.autofill;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.content.Context; import android.content.Context;
import android.util.Log;
import android.view.View; import android.view.View;
import android.widget.AdapterView; import android.widget.AdapterView;
import android.widget.ListPopupWindow;
import android.widget.PopupWindow;
import org.chromium.base.ApiCompatibilityUtils; import org.chromium.base.ApiCompatibilityUtils;
import org.chromium.ui.DropdownAdapter; import org.chromium.ui.DropdownAdapter;
...@@ -15,6 +18,7 @@ import org.chromium.ui.DropdownItem; ...@@ -15,6 +18,7 @@ import org.chromium.ui.DropdownItem;
import org.chromium.ui.DropdownPopupWindow; import org.chromium.ui.DropdownPopupWindow;
import org.chromium.ui.base.ViewAndroidDelegate; import org.chromium.ui.base.ViewAndroidDelegate;
import java.lang.reflect.Method;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashSet; import java.util.HashSet;
...@@ -23,7 +27,8 @@ import java.util.List; ...@@ -23,7 +27,8 @@ import java.util.List;
/** /**
* The Autofill suggestion popup that lists relevant suggestions. * The Autofill suggestion popup that lists relevant suggestions.
*/ */
public class AutofillPopup extends DropdownPopupWindow implements AdapterView.OnItemClickListener { public class AutofillPopup extends DropdownPopupWindow implements AdapterView.OnItemClickListener,
PopupWindow.OnDismissListener {
/** /**
* Constants defining types of Autofill suggestion entries. * Constants defining types of Autofill suggestion entries.
...@@ -47,9 +52,9 @@ public class AutofillPopup extends DropdownPopupWindow implements AdapterView.On ...@@ -47,9 +52,9 @@ public class AutofillPopup extends DropdownPopupWindow implements AdapterView.On
*/ */
public interface AutofillPopupDelegate { public interface AutofillPopupDelegate {
/** /**
* Requests the controller to hide AutofillPopup. * Informs the controller the AutofillPopup was hidden.
*/ */
public void requestHide(); public void dismissed();
/** /**
* Handles the selection of an Autofill suggestion from an AutofillPopup. * Handles the selection of an Autofill suggestion from an AutofillPopup.
...@@ -71,6 +76,7 @@ public class AutofillPopup extends DropdownPopupWindow implements AdapterView.On ...@@ -71,6 +76,7 @@ public class AutofillPopup extends DropdownPopupWindow implements AdapterView.On
mAutofillCallback = autofillCallback; mAutofillCallback = autofillCallback;
setOnItemClickListener(this); setOnItemClickListener(this);
setOnDismissListener(this);
} }
/** /**
...@@ -96,21 +102,27 @@ public class AutofillPopup extends DropdownPopupWindow implements AdapterView.On ...@@ -96,21 +102,27 @@ public class AutofillPopup extends DropdownPopupWindow implements AdapterView.On
show(); show();
ApiCompatibilityUtils.setLayoutDirection(getListView(), ApiCompatibilityUtils.setLayoutDirection(getListView(),
isRtl ? View.LAYOUT_DIRECTION_RTL : View.LAYOUT_DIRECTION_LTR); isRtl ? View.LAYOUT_DIRECTION_RTL : View.LAYOUT_DIRECTION_LTR);
}
/** // HACK: The ListPopupWindow's mPopup automatically dismisses on an outside tap. There's
* Overrides the default dismiss behavior to request the controller to dismiss the view. // no way to override it or prevent it, except reaching into ListPopupWindow's hidden
*/ // API. This allows the C++ controller to completely control showing/hiding the popup.
@Override // See http://crbug.com/400601
public void dismiss() { try {
mAutofillCallback.requestHide(); Method setForceIgnoreOutsideTouch = ListPopupWindow.class.getMethod(
"setForceIgnoreOutsideTouch", new Class[] { boolean.class });
setForceIgnoreOutsideTouch.invoke(this, new Object[] { true });
} catch (Exception e) {
Log.e("AutofillPopup",
"ListPopupWindow.setForceIgnoreOutsideTouch not found",
e);
}
} }
/** /**
* Hides the popup. * Hides the popup.
*/ */
public void hide() { public void hide() {
super.dismiss(); dismiss();
} }
@Override @Override
...@@ -120,4 +132,9 @@ public class AutofillPopup extends DropdownPopupWindow implements AdapterView.On ...@@ -120,4 +132,9 @@ public class AutofillPopup extends DropdownPopupWindow implements AdapterView.On
assert listIndex > -1; assert listIndex > -1;
mAutofillCallback.suggestionSelected(listIndex); mAutofillCallback.suggestionSelected(listIndex);
} }
@Override
public void onDismiss() {
mAutofillCallback.dismissed();
}
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment