0

Remove items on long press in keyboard accessory.

BUG=428087

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

Cr-Commit-Position: refs/heads/master@{#343764}
This commit is contained in:
rouslan
2015-08-17 15:46:39 -07:00
committed by Commit bot
parent 468590800d
commit c752712ead
9 changed files with 144 additions and 74 deletions
android_webview/java/src/org/chromium/android_webview
chrome
android
java
javatests
src
org
chromium
chrome
browser
browser
ui/android/java/src/org/chromium/ui/autofill

@ -10,6 +10,7 @@ import org.chromium.base.annotations.CalledByNative;
import org.chromium.base.annotations.JNINamespace;
import org.chromium.content.browser.ContentViewCore;
import org.chromium.ui.DropdownItem;
import org.chromium.ui.autofill.AutofillDelegate;
import org.chromium.ui.autofill.AutofillPopup;
import org.chromium.ui.autofill.AutofillSuggestion;
@ -49,7 +50,7 @@ public class AwAutofillClient {
mAutofillPopup = new AutofillPopup(
mContentViewCore.getContext(),
mContentViewCore.getViewAndroidDelegate(),
new AutofillPopup.AutofillPopupDelegate() {
new AutofillDelegate() {
@Override
public void dismissed() { }
@Override

@ -4,12 +4,17 @@
package org.chromium.chrome.browser.autofill;
import android.content.Context;
import android.content.DialogInterface;
import android.support.v7.app.AlertDialog;
import org.chromium.base.annotations.CalledByNative;
import org.chromium.base.annotations.JNINamespace;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.ResourceId;
import org.chromium.ui.DropdownItem;
import org.chromium.ui.autofill.AutofillDelegate;
import org.chromium.ui.autofill.AutofillKeyboardAccessory;
import org.chromium.ui.autofill.AutofillKeyboardAccessory.AutofillKeyboardAccessoryDelegate;
import org.chromium.ui.autofill.AutofillSuggestion;
import org.chromium.ui.base.WindowAndroid;
@ -19,9 +24,11 @@ import org.chromium.ui.base.WindowAndroid;
* --enable-autofill-keyboard-accessory-view is passed on the command line.
*/
@JNINamespace("autofill")
public class AutofillKeyboardAccessoryBridge implements AutofillKeyboardAccessoryDelegate {
public class AutofillKeyboardAccessoryBridge
implements AutofillDelegate, DialogInterface.OnClickListener {
private long mNativeAutofillKeyboardAccessory;
private AutofillKeyboardAccessory mAccessoryView;
private Context mContext;
private AutofillKeyboardAccessoryBridge() {
}
@ -43,6 +50,19 @@ public class AutofillKeyboardAccessoryBridge implements AutofillKeyboardAccessor
nativeSuggestionSelected(mNativeAutofillKeyboardAccessory, listIndex);
}
@Override
public void deleteSuggestion(int listIndex) {
if (mNativeAutofillKeyboardAccessory == 0) return;
nativeDeletionRequested(mNativeAutofillKeyboardAccessory, listIndex);
}
@Override
public void onClick(DialogInterface dialog, int which) {
assert which == DialogInterface.BUTTON_POSITIVE;
if (mNativeAutofillKeyboardAccessory == 0) return;
nativeDeletionConfirmed(mNativeAutofillKeyboardAccessory);
}
/**
* Initializes this object.
* This function should be called at most one time.
@ -59,6 +79,7 @@ public class AutofillKeyboardAccessoryBridge implements AutofillKeyboardAccessor
mNativeAutofillKeyboardAccessory = nativeAutofillKeyboardAccessory;
mAccessoryView = new AutofillKeyboardAccessory(windowAndroid, this);
mContext = windowAndroid.getActivity().get();
}
/**
@ -75,6 +96,7 @@ public class AutofillKeyboardAccessoryBridge implements AutofillKeyboardAccessor
@CalledByNative
private void dismiss() {
if (mAccessoryView != null) mAccessoryView.dismiss();
mContext = null;
}
/**
@ -90,6 +112,17 @@ public class AutofillKeyboardAccessoryBridge implements AutofillKeyboardAccessor
// should
// eventually disappear).
@CalledByNative
private void confirmDeletion(String title, String body) {
new AlertDialog.Builder(mContext, R.style.AlertDialogTheme)
.setTitle(title)
.setMessage(body)
.setNegativeButton(R.string.cancel, null)
.setPositiveButton(R.string.ok, this)
.create()
.show();
}
@CalledByNative
private static AutofillSuggestion[] createAutofillSuggestionArray(int size) {
return new AutofillSuggestion[size];
@ -114,12 +147,15 @@ public class AutofillKeyboardAccessoryBridge implements AutofillKeyboardAccessor
*/
@CalledByNative
private static void addToAutofillSuggestionArray(AutofillSuggestion[] array, int index,
String label, String sublabel, int iconId, int suggestionId) {
String label, String sublabel, int iconId, int suggestionId, boolean deletable) {
int drawableId = iconId == 0 ? DropdownItem.NO_ICON : ResourceId.mapToDrawableId(iconId);
array[index] = new AutofillSuggestion(label, sublabel, drawableId, suggestionId, false);
array[index] = new AutofillSuggestion(label, sublabel, drawableId, suggestionId, deletable);
}
private native void nativeViewDismissed(long nativeAutofillKeyboardAccessoryView);
private native void nativeSuggestionSelected(
long nativeAutofillKeyboardAccessoryView, int listIndex);
private native void nativeDeletionRequested(
long nativeAutofillKeyboardAccessoryView, int listIndex);
private native void nativeDeletionConfirmed(long nativeAutofillKeyboardAccessoryView);
}

@ -15,8 +15,8 @@ import org.chromium.base.annotations.JNINamespace;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.ResourceId;
import org.chromium.ui.DropdownItem;
import org.chromium.ui.autofill.AutofillDelegate;
import org.chromium.ui.autofill.AutofillPopup;
import org.chromium.ui.autofill.AutofillPopup.AutofillPopupDelegate;
import org.chromium.ui.autofill.AutofillSuggestion;
import org.chromium.ui.base.ViewAndroidDelegate;
import org.chromium.ui.base.WindowAndroid;
@ -25,7 +25,7 @@ import org.chromium.ui.base.WindowAndroid;
* JNI call glue for AutofillExternalDelagate C++ and Java objects.
*/
@JNINamespace("autofill")
public class AutofillPopupBridge implements AutofillPopupDelegate, DialogInterface.OnClickListener {
public class AutofillPopupBridge implements AutofillDelegate, DialogInterface.OnClickListener {
private final long mNativeAutofillPopup;
private final AutofillPopup mAutofillPopup;
private AlertDialog mDeletionDialog;

@ -17,8 +17,8 @@ import org.chromium.content.browser.test.util.Criteria;
import org.chromium.content.browser.test.util.CriteriaHelper;
import org.chromium.content.browser.test.util.TouchCommon;
import org.chromium.ui.DropdownItem;
import org.chromium.ui.autofill.AutofillDelegate;
import org.chromium.ui.autofill.AutofillPopup;
import org.chromium.ui.autofill.AutofillPopup.AutofillPopupDelegate;
import org.chromium.ui.autofill.AutofillSuggestion;
import org.chromium.ui.base.ActivityWindowAndroid;
import org.chromium.ui.base.ViewAndroidDelegate;
@ -69,7 +69,7 @@ public class AutofillTest extends ChromeActivityTestCaseBase<ChromeActivity> {
private static final long CALLBACK_TIMEOUT_MS = scaleTimeout(4000);
private static final int CHECK_INTERVAL_MS = 100;
private class MockAutofillCallback implements AutofillPopupDelegate{
private class MockAutofillCallback implements AutofillDelegate {
private final AtomicBoolean mGotPopupSelection = new AtomicBoolean(false);
public int mListIndex = -1;

@ -22,7 +22,8 @@ namespace autofill {
AutofillKeyboardAccessoryView::AutofillKeyboardAccessoryView(
AutofillPopupController* controller)
: controller_(controller) {
: controller_(controller),
deleting_index_(-1) {
JNIEnv* env = base::android::AttachCurrentThread();
java_object_.Reset(Java_AutofillKeyboardAccessoryBridge_create(env));
}
@ -66,11 +67,13 @@ void AutofillKeyboardAccessoryView::UpdateBoundsAndRedrawPopup() {
controller_->GetIconResourceID(suggestion.icon));
}
bool deletable =
controller_->GetRemovalConfirmationText(i, nullptr, nullptr);
Java_AutofillKeyboardAccessoryBridge_addToAutofillSuggestionArray(
env, data_array.obj(), i,
base::android::ConvertUTF16ToJavaString(env, suggestion.value).obj(),
base::android::ConvertUTF16ToJavaString(env, suggestion.label).obj(),
android_icon_id, suggestion.frontend_id);
android_icon_id, suggestion.frontend_id, deletable);
}
Java_AutofillKeyboardAccessoryBridge_show(
@ -85,6 +88,34 @@ void AutofillKeyboardAccessoryView::SuggestionSelected(JNIEnv* env,
controller_->AcceptSuggestion(list_index);
}
void AutofillKeyboardAccessoryView::DeletionRequested(JNIEnv* env,
jobject obj,
jint list_index) {
if (!controller_)
return;
base::string16 confirmation_title, confirmation_body;
if (!controller_->GetRemovalConfirmationText(list_index, &confirmation_title,
&confirmation_body)) {
return;
}
deleting_index_ = list_index;
Java_AutofillKeyboardAccessoryBridge_confirmDeletion(
env, java_object_.obj(),
base::android::ConvertUTF16ToJavaString(env, confirmation_title).obj(),
base::android::ConvertUTF16ToJavaString(env, confirmation_body).obj());
}
void AutofillKeyboardAccessoryView::DeletionConfirmed(JNIEnv* env,
jobject obj) {
if (!controller_)
return;
CHECK_GE(deleting_index_, 0);
controller_->RemoveSuggestion(deleting_index_);
}
void AutofillKeyboardAccessoryView::ViewDismissed(JNIEnv* env, jobject obj) {
if (controller_)
controller_->ViewDestroyed();

@ -33,6 +33,10 @@ class AutofillKeyboardAccessoryView : public AutofillPopupView {
// Called when an autofill item was selected.
void SuggestionSelected(JNIEnv* env, jobject obj, jint list_index);
void DeletionRequested(JNIEnv* env, jobject obj, jint list_index);
void DeletionConfirmed(JNIEnv* env, jobject obj);
void ViewDismissed(JNIEnv* env, jobject obj);
static bool RegisterAutofillKeyboardAccessoryView(JNIEnv* env);
@ -49,6 +53,10 @@ class AutofillKeyboardAccessoryView : public AutofillPopupView {
AutofillPopupController* controller_; // weak.
// The index of the last item the user long-pressed (they will be shown a
// confirmation dialog).
int deleting_index_;
// The corresponding java object.
base::android::ScopedJavaGlobalRef<jobject> java_object_;

@ -0,0 +1,28 @@
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.ui.autofill;
/**
* An interface to handle the touch interaction with an autofill popup or keyboard accessory.
*/
public interface AutofillDelegate {
/**
* Informs the controller the AutofillPopup or AutofillKeyboardAccessory was hidden.
*/
public void dismissed();
/**
* Handles the selection of an Autofill suggestion from an AutofillPopup or
* AutofillKeyboardAccessory.
* @param listIndex The index of the selected Autofill suggestion.
*/
public void suggestionSelected(int listIndex);
/**
* Initiates the deletion process for an item. (A confirm dialog should be shown.)
* @param listIndex The index of the suggestion to delete.
*/
public void deleteSuggestion(int listIndex);
}

@ -26,41 +26,26 @@ import org.chromium.ui.gfx.DeviceDisplayInfo;
* below the content area.
*/
public class AutofillKeyboardAccessory extends LinearLayout
implements WindowAndroid.KeyboardVisibilityListener, View.OnClickListener {
implements WindowAndroid.KeyboardVisibilityListener, View.OnClickListener,
View.OnLongClickListener {
private final WindowAndroid mWindowAndroid;
private final AutofillKeyboardAccessoryDelegate mAutofillCallback;
private final AutofillDelegate mAutofillDelegate;
private final int mMaximumLabelWidthPx;
private final int mMaximumSublabelWidthPx;
/**
* An interface to handle the touch interaction with an AutofillKeyboardAccessory object.
*/
public interface AutofillKeyboardAccessoryDelegate {
/**
* Informs the controller the AutofillKeyboardAccessory was hidden.
*/
public void dismissed();
/**
* Handles the selection of an Autofill suggestion from an AutofillKeyboardAccessory.
* @param listIndex The index of the selected Autofill suggestion.
*/
public void suggestionSelected(int listIndex);
}
/**
* Creates an AutofillKeyboardAccessory with specified parameters.
* @param windowAndroid The owning WindowAndroid.
* @param autofillCallback A object that handles the calls to the native
* AutofillKeyboardAccessoryView.
* @param autofillDelegate A object that handles the calls to the native
* AutofillKeyboardAccessoryView.
*/
public AutofillKeyboardAccessory(
WindowAndroid windowAndroid, AutofillKeyboardAccessoryDelegate autofillCallback) {
WindowAndroid windowAndroid, AutofillDelegate autofillDelegate) {
super(windowAndroid.getActivity().get());
assert autofillCallback != null;
assert autofillDelegate != null;
assert windowAndroid.getActivity().get() != null;
mWindowAndroid = windowAndroid;
mAutofillCallback = autofillCallback;
mAutofillDelegate = autofillDelegate;
int deviceWidthPx = DeviceDisplayInfo.create(getContext()).getDisplayWidth();
mMaximumLabelWidthPx = deviceWidthPx / 2;
@ -82,7 +67,8 @@ public class AutofillKeyboardAccessory extends LinearLayout
@SuppressLint("InlinedApi")
public void showWithSuggestions(AutofillSuggestion[] suggestions, boolean isRtl) {
removeAllViews();
for (AutofillSuggestion suggestion : suggestions) {
for (int i = 0; i < suggestions.length; i++) {
AutofillSuggestion suggestion = suggestions[i];
assert !TextUtils.isEmpty(suggestion.getLabel());
View touchTarget;
@ -119,7 +105,12 @@ public class AutofillKeyboardAccessory extends LinearLayout
}
}
touchTarget.setTag(i);
touchTarget.setOnClickListener(this);
if (suggestion.isDeletable()) {
touchTarget.setOnLongClickListener(this);
}
addView(touchTarget);
}
@ -149,20 +140,18 @@ public class AutofillKeyboardAccessory extends LinearLayout
public void keyboardVisibilityChanged(boolean isShowing) {
if (!isShowing) {
dismiss();
mAutofillCallback.dismissed();
mAutofillDelegate.dismissed();
}
}
@Override
public void onClick(View v) {
int count = getChildCount();
for (int i = 0; i < count; i++) {
if (getChildAt(i) == v) {
mAutofillCallback.suggestionSelected(i);
return;
}
}
mAutofillDelegate.suggestionSelected((int) v.getTag());
}
assert false;
@Override
public boolean onLongClick(View v) {
mAutofillDelegate.deleteSuggestion((int) v.getTag());
return true;
}
}

@ -34,43 +34,20 @@ public class AutofillPopup extends DropdownPopupWindow implements AdapterView.On
private static final int ITEM_ID_SEPARATOR_ENTRY = -3;
private final Context mContext;
private final AutofillPopupDelegate mAutofillCallback;
private final AutofillDelegate mAutofillDelegate;
private List<AutofillSuggestion> mSuggestions;
/**
* An interface to handle the touch interaction with an AutofillPopup object.
*/
public interface AutofillPopupDelegate {
/**
* Informs the controller the AutofillPopup was hidden.
*/
public void dismissed();
/**
* Handles the selection of an Autofill suggestion from an AutofillPopup.
* @param listIndex The index of the selected Autofill suggestion.
*/
public void suggestionSelected(int listIndex);
/**
* Initiates the deletion process for an item. (A confirm dialog should be shown.)
* @param listIndex The index of the suggestion to delete.
*/
public void deleteSuggestion(int listIndex);
}
/**
* Creates an AutofillWindow with specified parameters.
* @param context Application context.
* @param viewAndroidDelegate View delegate used to add and remove views.
* @param autofillCallback A object that handles the calls to the native AutofillPopupView.
* @param autofillDelegate An object that handles the calls to the native AutofillPopupView.
*/
public AutofillPopup(Context context, ViewAndroidDelegate viewAndroidDelegate,
AutofillPopupDelegate autofillCallback) {
AutofillDelegate autofillDelegate) {
super(context, viewAndroidDelegate);
mContext = context;
mAutofillCallback = autofillCallback;
mAutofillDelegate = autofillDelegate;
setOnItemClickListener(this);
setOnDismissListener(this);
@ -109,7 +86,7 @@ public class AutofillPopup extends DropdownPopupWindow implements AdapterView.On
DropdownAdapter adapter = (DropdownAdapter) parent.getAdapter();
int listIndex = mSuggestions.indexOf(adapter.getItem(position));
assert listIndex > -1;
mAutofillCallback.suggestionSelected(listIndex);
mAutofillDelegate.suggestionSelected(listIndex);
}
@Override
@ -120,12 +97,12 @@ public class AutofillPopup extends DropdownPopupWindow implements AdapterView.On
int listIndex = mSuggestions.indexOf(suggestion);
assert listIndex > -1;
mAutofillCallback.deleteSuggestion(listIndex);
mAutofillDelegate.deleteSuggestion(listIndex);
return true;
}
@Override
public void onDismiss() {
mAutofillCallback.dismissed();
mAutofillDelegate.dismissed();
}
}