diff options
22 files changed, 638 insertions, 35 deletions
diff --git a/android_webview/lib/main/webview_stubs.cc b/android_webview/lib/main/webview_stubs.cc index 50179d2..de2a058 100644 --- a/android_webview/lib/main/webview_stubs.cc +++ b/android_webview/lib/main/webview_stubs.cc @@ -4,7 +4,6 @@ #include "chrome/browser/android/tab_android.h" #include "chrome/browser/api/infobars/confirm_infobar_delegate.h" -#include "chrome/browser/autofill/autofill_external_delegate.h" // This file contains temporary stubs to allow the libwebview target to compile. // They will be removed once real implementations are written/upstreamed, or @@ -18,15 +17,6 @@ TabAndroid* TabAndroid::FromWebContents(content::WebContents* web_contents) { } // static -void AutofillExternalDelegate::CreateForWebContentsAndManager( - content::WebContents* web_contents, - AutofillManager* autofill_manager) { - // We don't need to return a real AutofillExternalDelegate yet. - // Eventually, WebView will need an implementation (probably shared with - // Chrome). -} - -// static InfoBar* ConfirmInfoBarDelegate::CreateInfoBar(InfoBarService* owner) { return NULL; } diff --git a/base/android/jni_generator/jni_generator.py b/base/android/jni_generator/jni_generator.py index afc2389..431a6c2 100755 --- a/base/android/jni_generator/jni_generator.py +++ b/base/android/jni_generator/jni_generator.py @@ -153,7 +153,6 @@ def JavaParamToJni(param): ] app_param_list = [ 'Landroid/graphics/SurfaceTexture', - 'Lcom/google/android/apps/chrome/AutofillData', 'Lcom/google/android/apps/chrome/ChromeContextMenuInfo', 'Lcom/google/android/apps/chrome/ChromeWindow', 'Lcom/google/android/apps/chrome/OmniboxSuggestion', @@ -173,6 +172,8 @@ def JavaParamToJni(param): 'Lorg/chromium/android_webview/JsResultHandler', 'Lorg/chromium/android_webview/JsResultReceiver', 'Lorg/chromium/base/SystemMessageHandler', + 'Lorg/chromium/chrome/browser/autofill/AutofillExternalDelegate', + 'Lorg/chromium/chrome/browser/autofill/AutofillSuggestion', 'Lorg/chromium/chrome/browser/ChromeBrowserProvider$BookmarkNode', 'Lorg/chromium/chrome/browser/ChromeHttpAuthHandler', 'Lorg/chromium/chrome/browser/ChromeWebContentsDelegateAndroid', @@ -186,6 +187,7 @@ def JavaParamToJni(param): 'WebContentsDelegateAndroid'), 'Lorg/chromium/chrome/browser/database/SQLiteCursor', 'Lorg/chromium/content/app/SandboxedProcessService', + 'Lorg/chromium/content/browser/ContainerViewDelegate', 'Lorg/chromium/content/browser/ContentVideoView', 'Lorg/chromium/content/browser/ContentViewCore', 'Lorg/chromium/content/browser/DeviceOrientation', diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/AutofillExternalDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/AutofillExternalDelegate.java new file mode 100644 index 0000000..50ca016 --- /dev/null +++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/AutofillExternalDelegate.java @@ -0,0 +1,102 @@ +// Copyright (c) 2012 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.chrome.browser.autofill; + +import android.graphics.Rect; + +import org.chromium.base.CalledByNative; +import org.chromium.content.browser.ContainerViewDelegate; +import org.chromium.ui.gfx.NativeWindow; + +/** + * Android specific external delegate for display and selection of autofill data. + */ +public class AutofillExternalDelegate { + + // Area of the Autofill popup anchor position used to position the Autofill window. + private Rect mAutofillAnchorRect; + private AutofillWindow mAutofillWindow; + private final int mNativeAutofillExternalDelegate; + private final ContainerViewDelegate mContainerViewDelegate; + + /** + * Creates an AutofillExternalDelegate object. + * @param nativeAutofillExternalDelegate A pointer to the native AutofillExternalDelegate. + * @param containerViewDelegate A delegate that allows adding and removing views. + */ + public AutofillExternalDelegate(int nativeAutofillExternalDelegate, + ContainerViewDelegate containerViewDelegate) { + mNativeAutofillExternalDelegate = nativeAutofillExternalDelegate; + mContainerViewDelegate = containerViewDelegate; + } + + @CalledByNative + private static AutofillExternalDelegate create(int nativeAutofillExternalDelegate, + ContainerViewDelegate containerViewDelegate) { + return new AutofillExternalDelegate(nativeAutofillExternalDelegate, containerViewDelegate); + } + + /** + * Sets the autofill window's position in the proper space (window space). + */ + private void setAutofillWindowPosition() { + if (mAutofillWindow != null && mAutofillAnchorRect != null) { + mAutofillWindow.setPositionAround(mAutofillAnchorRect); + } + } + + /** + * Informs the native delegate that an Autofill suggestion has been chosen. + * @param listIndex The index of the autofill suggestion selected + * @param value The value of the autofill suggestion. + * @param uniqueId The unique ID of the autofill suggestion selected. + */ + public void autofillPopupSelected(int listIndex, String value, int uniqueId) { + if (mNativeAutofillExternalDelegate != 0) { + nativeAutofillPopupSelected( + mNativeAutofillExternalDelegate, listIndex, value, uniqueId); + } + } + + @SuppressWarnings("unused") + @CalledByNative + private void openAutofillPopup(NativeWindow nativeWindow, AutofillSuggestion[] data) { + if (mAutofillWindow == null) { + mAutofillWindow = new AutofillWindow(nativeWindow, mContainerViewDelegate, this, data); + } else { + mAutofillWindow.setAutofillSuggestions(data); + } + if (mAutofillAnchorRect != null) { + setAutofillWindowPosition(); + mAutofillWindow.show(); + } + } + + @SuppressWarnings("unused") + @CalledByNative + private void closeAutofillPopup() { + if (mAutofillWindow == null) return; + mAutofillWindow.dismiss(); + mAutofillWindow = null; + mAutofillAnchorRect = null; + } + + @SuppressWarnings("unused") + @CalledByNative + private void setAutofillAnchorRect(float x, float y, float width, float height) { + mAutofillAnchorRect = new Rect((int) x, (int) y, (int) (x + width), (int) (y + height)); + setAutofillWindowPosition(); + } + + @SuppressWarnings("unused") + @CalledByNative + private static AutofillSuggestion createAutofillSuggestion(String name, String label, + int uniqueId) { + return new AutofillSuggestion(name, label, uniqueId); + } + + private native void nativeAutofillPopupSelected(int nativeAutofillExternalDelegateAndroid, + int listIndex, String value, int uniqueId); +}
\ No newline at end of file diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/AutofillSuggestion.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/AutofillSuggestion.java new file mode 100644 index 0000000..4a5dfa4 --- /dev/null +++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/AutofillSuggestion.java @@ -0,0 +1,28 @@ +// Copyright (c) 2012 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.chrome.browser.autofill; + +import org.chromium.base.CalledByNative; + +/** + * Autofill suggestion container used to store information needed for each Autofill popup entry. + */ +class AutofillSuggestion { + public final String mName; + public final String mLabel; + public final int mUniqueId; + + /** + * Constructs a Autofill suggestion container. + * @param name The name of the Autofill suggestion. + * @param label The describing label of the Autofill suggestion. + * @param uniqueId The unique id used to identify the Autofill suggestion. + */ + AutofillSuggestion(String name, String label, int uniqueId) { + mName = name; + mLabel = label; + mUniqueId = uniqueId; + } +}
\ No newline at end of file diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/AutofillWindow.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/AutofillWindow.java new file mode 100644 index 0000000..cd48573 --- /dev/null +++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/AutofillWindow.java @@ -0,0 +1,203 @@ +// Copyright (c) 2012 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.chrome.browser.autofill; + +import android.content.Context; +import android.graphics.Paint; +import android.graphics.Point; +import android.graphics.Rect; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.WindowManager; +import android.widget.AdapterView; +import android.widget.ArrayAdapter; +import android.widget.ListAdapter; +import android.widget.ListPopupWindow; +import android.widget.PopupWindow; +import android.widget.TextView; + +import java.util.ArrayList; + +import org.chromium.content.app.AppResource; +import org.chromium.content.browser.ContainerViewDelegate; +import org.chromium.ui.gfx.NativeWindow; + +/** + * The Autofill suggestion window that lists relevant suggestions. + */ +public class AutofillWindow extends ListPopupWindow { + + private static final int TEXT_PADDING_DP = 30; + + private NativeWindow mNativeWindow; + private int mDesiredWidth; + private AnchorView mAnchorView; + private ContainerViewDelegate mContainerViewDelegate; + private Paint mNameViewPaint; + private Paint mLabelViewPaint; + + private static class AutofillListAdapter extends ArrayAdapter<AutofillSuggestion> { + private Context mContext; + + AutofillListAdapter(Context context, ArrayList<AutofillSuggestion> objects) { + super(context, AppResource.LAYOUT_AUTOFILL_TEXT, objects); + mContext = context; + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + View layout = convertView; + if (convertView == null) { + LayoutInflater inflater = + (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); + layout = inflater.inflate(AppResource.LAYOUT_AUTOFILL_TEXT, null); + } + TextView nameView = (TextView) layout.findViewById(AppResource.ID_AUTOFILL_NAME); + nameView.setText(getItem(position).mName); + TextView labelView = (TextView) layout.findViewById(AppResource.ID_AUTOFILL_LABEL); + labelView.setText(getItem(position).mLabel); + + return layout; + } + } + + // ListPopupWindow needs an anchor view to determine it's size and position. We create a view + // with the given desired width at the text edit area as a stand-in. This is "Fake" in the + // sense that it draws nothing, accepts no input, and thwarts all attempts at laying it out + // "properly". + private static class AnchorView extends View { + AnchorView(Context c) { + super(c); + } + + public void setSize(Rect r, int desiredWidth) { + setLeft(r.left); + // If the desired width is smaller than the text edit box, use the width of the text + // editbox. + if (desiredWidth < r.right - r.left) { + setRight(r.right); + } else { + // Make sure that the anchor view does not go outside the screen. + Point size = new Point(); + WindowManager wm = (WindowManager) getContext().getSystemService( + Context.WINDOW_SERVICE); + wm.getDefaultDisplay().getSize(size); + if (r.left + desiredWidth > size.x) { + setRight(size.x); + } else { + setRight(r.left + desiredWidth); + } + } + setBottom(r.bottom); + setTop(r.top); + } + } + + + /** + * Creates an AutofillWindow with specified parameters. + * @param nativeWindow NativeWindow used to get application context. + * @param ContainerViewDelegate View delegate used to add and remove views. + * @param autofillExternalDelegate The autofill delegate. + * @param data The autofill suggestions. + */ + public AutofillWindow(NativeWindow nativeWindow, ContainerViewDelegate ContainerViewDelegate, + final AutofillExternalDelegate autofillExternalDelegate, AutofillSuggestion[] data) { + super(nativeWindow.getContext()); + mNativeWindow = nativeWindow; + mContainerViewDelegate = ContainerViewDelegate; + setAutofillSuggestions(data); + setOnItemClickListener(new AdapterView.OnItemClickListener() { + @Override + public void onItemClick(AdapterView<?> parent, View view, int position, long id) { + try { + ListAdapter adapter = (ListAdapter) parent.getAdapter(); + AutofillSuggestion data = (AutofillSuggestion) adapter.getItem(position); + autofillExternalDelegate.autofillPopupSelected(position, data.mName, + data.mUniqueId); + } catch (ClassCastException e) { + Log.w("AutofillWindow", "error in onItemClick", e); + assert false; + } + } + }); + setWidth(ListPopupWindow.WRAP_CONTENT); + } + + /** + * Sets the position of the autofill popup "around" the input rectangle. + * @param r The rectangle location for the autofill popup. + */ + public void setPositionAround(Rect r) { + if (mAnchorView == null) { + mAnchorView = new AnchorView(mNativeWindow.getContext()); + mContainerViewDelegate.addViewToContainerView(mAnchorView); + // When the popup goes away we have to remove the fake anchor view. + setOnDismissListener(new PopupWindow.OnDismissListener() { + @Override + public void onDismiss() { + mContainerViewDelegate.removeViewFromContainerView(mAnchorView); + mAnchorView = null; + } + }); + } + mAnchorView.setSize(r, mDesiredWidth); + setAnchorView(mAnchorView); + } + + /** + * Sets the autofill data to display in the popup. + * @param data Autofill suggestion data. + */ + public void setAutofillSuggestions(AutofillSuggestion[] data) { + // Remove the AutofillSuggestions with IDs that are unsupported by Android + ArrayList<AutofillSuggestion> cleanedData = new ArrayList<AutofillSuggestion>(); + for (int i = 0; i < data.length; i++) { + if (data[i].mUniqueId >= 0) cleanedData.add(data[i]); + } + + mDesiredWidth = getDesiredWidth(data); + setAdapter(new AutofillListAdapter(mNativeWindow.getContext(), cleanedData)); + } + + /** + * Get desired popup window width by calculating the maximum text length from Autofill data. + * @param data Autofill suggestion data. + * @return The popup window width. + */ + private int getDesiredWidth(AutofillSuggestion[] data) { + if (mNameViewPaint == null || mLabelViewPaint == null) { + LayoutInflater inflater = + (LayoutInflater) mNativeWindow.getContext().getSystemService( + Context.LAYOUT_INFLATER_SERVICE); + View layout = inflater.inflate(AppResource.LAYOUT_AUTOFILL_TEXT, null); + TextView nameView = (TextView) layout.findViewById(AppResource.ID_AUTOFILL_NAME); + mNameViewPaint = nameView.getPaint(); + TextView labelView = (TextView) layout.findViewById(AppResource.ID_AUTOFILL_LABEL); + mLabelViewPaint = labelView.getPaint(); + } + + int maxTextWidth = 0; + Rect bounds = new Rect(); + for (int i = 0; i < data.length; ++i) { + bounds.setEmpty(); + String name = data[i].mName; + int width = 0; + mNameViewPaint.getTextBounds(name, 0, name.length(), bounds); + width += bounds.width(); + + bounds.setEmpty(); + String label = data[i].mLabel; + mLabelViewPaint.getTextBounds(label, 0, label.length(), bounds); + width += bounds.width(); + maxTextWidth = Math.max(width, maxTextWidth); + } + // Adding padding. + return maxTextWidth + (int) (TEXT_PADDING_DP * + mNativeWindow.getContext().getResources().getDisplayMetrics().density); + } +} diff --git a/chrome/android/testshell/java/src/org/chromium/chrome/testshell/ChromiumTestShellActivity.java b/chrome/android/testshell/java/src/org/chromium/chrome/testshell/ChromiumTestShellActivity.java index fada504..5887a69 100644 --- a/chrome/android/testshell/java/src/org/chromium/chrome/testshell/ChromiumTestShellActivity.java +++ b/chrome/android/testshell/java/src/org/chromium/chrome/testshell/ChromiumTestShellActivity.java @@ -119,6 +119,9 @@ public class ChromiumTestShellActivity extends Activity { private void initializeContentViewResources() { AppResource.DIMENSION_LINK_PREVIEW_OVERLAY_RADIUS = R.dimen.link_preview_overlay_radius; AppResource.DRAWABLE_LINK_PREVIEW_POPUP_OVERLAY = R.drawable.popup_zoomer_overlay; + AppResource.ID_AUTOFILL_LABEL = R.id.autofill_label; + AppResource.ID_AUTOFILL_NAME = R.id.autofill_name; + AppResource.LAYOUT_AUTOFILL_TEXT = R.layout.autofill_text; AppResource.STRING_CONTENT_VIEW_CONTENT_DESCRIPTION = R.string.accessibility_content_view; AppResource.STRING_MEDIA_PLAYER_MESSAGE_PLAYBACK_ERROR = R.string.media_player_error_text_invalid_progressive_playback; diff --git a/chrome/android/testshell/res/layout/autofill_text.xml b/chrome/android/testshell/res/layout/autofill_text.xml new file mode 100644 index 0000000..0a9e113 --- /dev/null +++ b/chrome/android/testshell/res/layout/autofill_text.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="utf-8"?> + +<!-- Copyright (c) 2012 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. + --> + +<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_height="fill_parent" + android:layout_width="fill_parent" + android:orientation="horizontal"> + <TextView android:id="@+id/autofill_name" + android:layout_alignParentLeft="true" + android:layout_width="fill_parent" + android:layout_height="fill_parent" + android:background="#FFF" + android:padding="5dp" + android:textSize="18sp" + android:textColor="#000"/> + <TextView android:id="@+id/autofill_label" + android:layout_alignParentRight="true" + android:layout_width="wrap_content" + android:layout_height="fill_parent" + android:padding="5dp" + android:textSize="18sp" + android:background="#FFF" + android:textColor="#CCC"/> +</RelativeLayout>
\ No newline at end of file diff --git a/chrome/android/testshell/testshell_stubs.cc b/chrome/android/testshell/testshell_stubs.cc index 67edc68..10798d4 100644 --- a/chrome/android/testshell/testshell_stubs.cc +++ b/chrome/android/testshell/testshell_stubs.cc @@ -4,7 +4,6 @@ #include "base/logging.h" #include "chrome/browser/android/tab_android.h" -#include "chrome/browser/autofill/autofill_external_delegate.h" #include "chrome/browser/api/infobars/confirm_infobar_delegate.h" // This file contains temporary stubs to allow the libtestshell target to @@ -17,12 +16,6 @@ TabAndroid* TabAndroid::FromWebContents(content::WebContents* web_contents) { return NULL; } -// static -void AutofillExternalDelegate::CreateForWebContentsAndManager( - content::WebContents* web_contents, - AutofillManager* autofill_manager) { -} - InfoBar* ConfirmInfoBarDelegate::CreateInfoBar(InfoBarService* owner) { NOTIMPLEMENTED(); return NULL; diff --git a/chrome/browser/android/chrome_jni_registrar.cc b/chrome/browser/android/chrome_jni_registrar.cc index 5d5db92..d8c5e94 100644 --- a/chrome/browser/android/chrome_jni_registrar.cc +++ b/chrome/browser/android/chrome_jni_registrar.cc @@ -13,12 +13,15 @@ #include "chrome/browser/android/provider/chrome_browser_provider.h" #include "chrome/browser/component/web_contents_delegate_android/component_jni_registrar.h" #include "chrome/browser/history/android/sqlite_cursor.h" +#include "chrome/browser/ui/android/autofill/autofill_external_delegate.h" #include "chrome/browser/ui/android/javascript_app_modal_dialog_android.h" namespace chrome { namespace android { static base::android::RegistrationMethod kChromeRegisteredMethods[] = { + { "AutofillExternalDelegate", + AutofillExternalDelegateAndroid::RegisterAutofillExternalDelegate}, { "ChromeBrowserProvider", ChromeBrowserProvider::RegisterChromeBrowserProvider }, { "ChromeWebContentsDelegateAndroid", diff --git a/chrome/browser/autofill/test_autofill_external_delegate_android.cc b/chrome/browser/autofill/test_autofill_external_delegate_android.cc deleted file mode 100644 index 4e42fdf..0000000 --- a/chrome/browser/autofill/test_autofill_external_delegate_android.cc +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) 2012 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. - -#include "chrome/browser/autofill/test_autofill_external_delegate.h" - -void AutofillExternalDelegate::CreateForWebContentsAndManager( - content::WebContents* web_contents, - AutofillManager* autofill_manager) { - if (FromWebContents(web_contents)) - return; - - web_contents->SetUserData( - UserDataKey(), - new TestAutofillExternalDelegate(web_contents, autofill_manager)); -} diff --git a/chrome/browser/ui/android/autofill/autofill_external_delegate.cc b/chrome/browser/ui/android/autofill/autofill_external_delegate.cc new file mode 100644 index 0000000..7399034 --- /dev/null +++ b/chrome/browser/ui/android/autofill/autofill_external_delegate.cc @@ -0,0 +1,126 @@ +// Copyright (c) 2012 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. + +#include "chrome/browser/ui/android/autofill/autofill_external_delegate.h" + +#include "base/android/jni_android.h" +#include "base/android/scoped_java_ref.h" +#include "base/android/jni_string.h" +#include "base/string_util.h" +#include "chrome/browser/autofill/autofill_manager.h" +#include "chrome/browser/ui/android/window_android_helper.h" +#include "content/public/browser/android/content_view_core.h" +#include "content/public/browser/browser_thread.h" +#include "content/public/browser/render_view_host.h" +#include "content/public/browser/web_contents.h" +#include "jni/AutofillExternalDelegate_jni.h" +#include "ui/gfx/android/window_android.h" +#include "ui/gfx/rect.h" + +using base::android::MethodID; +using content::BrowserThread; + +void AutofillExternalDelegate::CreateForWebContentsAndManager( + content::WebContents* web_contents, + AutofillManager* autofill_manager) { + if (FromWebContents(web_contents)) + return; + + web_contents->SetUserData( + UserDataKey(), + new AutofillExternalDelegateAndroid(web_contents, autofill_manager)); +} + +AutofillExternalDelegateAndroid::AutofillExternalDelegateAndroid( + content::WebContents* web_contents, AutofillManager* manager) + : AutofillExternalDelegate(web_contents, manager) { + content::ContentViewCore* content_view_core = + content::ContentViewCore::FromWebContents(web_contents); + + JNIEnv* env = base::android::AttachCurrentThread(); + base::android::ScopedJavaLocalRef<jobject> container_view_delegate; + // content_view_core should only be NULL for testing. + if (content_view_core) { + container_view_delegate = content_view_core->GetContainerViewDelegate(); + } + + java_object_.Reset(Java_AutofillExternalDelegate_create(env, + reinterpret_cast<jint>(this), container_view_delegate.obj())); +} + +AutofillExternalDelegateAndroid::~AutofillExternalDelegateAndroid() {} + +void AutofillExternalDelegateAndroid::AutofillPopupSelected(JNIEnv *env, + jobject obj, + jint list_index, + jstring value, + jint unique_id) { + string16 value_utf16 = base::android::ConvertJavaStringToUTF16(env, value); + DidAcceptAutofillSuggestions(value_utf16, unique_id, list_index); +} + +void AutofillExternalDelegateAndroid::ApplyAutofillSuggestions( + const std::vector<string16>& autofill_values, + const std::vector<string16>& autofill_labels, + const std::vector<string16>& autofill_icons, + const std::vector<int>& autofill_unique_ids) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + + // We need an array of AutofillSuggestion. + JNIEnv* env = base::android::AttachCurrentThread(); + ScopedJavaLocalRef<jclass> autofill_suggestion_clazz = + base::android::GetClass(env, + "org/chromium/chrome/browser/autofill/AutofillSuggestion"); + ScopedJavaLocalRef<jobjectArray> data_array(env, + env->NewObjectArray(autofill_values.size(), + autofill_suggestion_clazz.obj(), NULL)); + base::android::CheckException(env); + for (size_t i = 0; i < autofill_values.size(); ++i) { + ScopedJavaLocalRef<jstring> value = + base::android::ConvertUTF16ToJavaString(env, autofill_values[i]); + ScopedJavaLocalRef<jstring> label = + base::android::ConvertUTF16ToJavaString(env, autofill_labels[i]); + int unique_id = autofill_unique_ids[i]; + ScopedJavaLocalRef<jobject> data = + Java_AutofillExternalDelegate_createAutofillSuggestion(env, + value.obj(), + label.obj(), + unique_id); + env->SetObjectArrayElement(data_array.obj(), i, data.obj()); + base::android::CheckException(env); + } + ui::WindowAndroid* window_android = + WindowAndroidHelper::FromWebContents(web_contents())->GetWindowAndroid(); + Java_AutofillExternalDelegate_openAutofillPopup(env, java_object_.obj(), + window_android->GetJavaObject().obj(), data_array.obj()); +} + +void AutofillExternalDelegateAndroid::OnQueryPlatformSpecific( + int query_id, + const FormData& form, + const FormFieldData& field, + const gfx::Rect& bounds) { + SetBounds(bounds); +} + +void AutofillExternalDelegateAndroid::HideAutofillPopupInternal() { + JNIEnv* env = base::android::AttachCurrentThread(); + Java_AutofillExternalDelegate_closeAutofillPopup(env, java_object_.obj()); +} + +void AutofillExternalDelegateAndroid::SetBounds(const gfx::Rect& bounds) { + JNIEnv* env = base::android::AttachCurrentThread(); + Java_AutofillExternalDelegate_setAutofillAnchorRect(env, + java_object_.obj(), + bounds.x(), + bounds.y(), + bounds.width(), + bounds.height()); +} + +// static +bool AutofillExternalDelegateAndroid::RegisterAutofillExternalDelegate( + JNIEnv* env) { + return RegisterNativesImpl(env); +} diff --git a/chrome/browser/ui/android/autofill/autofill_external_delegate.h b/chrome/browser/ui/android/autofill/autofill_external_delegate.h new file mode 100644 index 0000000..d565f8d --- /dev/null +++ b/chrome/browser/ui/android/autofill/autofill_external_delegate.h @@ -0,0 +1,64 @@ +// Copyright (c) 2012 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. + +#ifndef CHROME_BROWSER_UI_ANDROID_AUTOFILL_AUTOFILL_EXTERNAL_DELEGATE_H_ +#define CHROME_BROWSER_UI_ANDROID_AUTOFILL_AUTOFILL_EXTERNAL_DELEGATE_H_ + +#include <jni.h> +#include <map> +#include <vector> + +#include "base/android/scoped_java_ref.h" +#include "base/compiler_specific.h" +#include "base/string16.h" +#include "chrome/browser/autofill/autofill_external_delegate.h" +#include "chrome/common/form_data.h" +#include "chrome/common/form_field_data.h" + +class AutofillManager; + +namespace content { +class WebContents; +} + +// Android implementation of external delegate for display and selection of +// Autofill suggestions. +class AutofillExternalDelegateAndroid : public AutofillExternalDelegate { + public: + AutofillExternalDelegateAndroid(content::WebContents* web_contents, + AutofillManager* manager); + virtual ~AutofillExternalDelegateAndroid(); + + // -------------------------------------------------------------------------- + // Methods called from Java via JNI + // -------------------------------------------------------------------------- + // Called when an autofill item was selected. + void AutofillPopupSelected(JNIEnv* env, + jobject obj, + jint list_index, + jstring value, + jint unique_id); + + static bool RegisterAutofillExternalDelegate(JNIEnv* env); + + private: + virtual void ApplyAutofillSuggestions( + const std::vector<string16>& autofill_values, + const std::vector<string16>& autofill_labels, + const std::vector<string16>& autofill_icons, + const std::vector<int>& autofill_unique_ids) OVERRIDE; + virtual void OnQueryPlatformSpecific(int query_id, + const FormData& form, + const FormFieldData& field, + const gfx::Rect& bounds) OVERRIDE; + virtual void HideAutofillPopupInternal() OVERRIDE; + virtual void SetBounds(const gfx::Rect& bounds) OVERRIDE; + + // The corresponding AutofillExternalDelegate java object. + base::android::ScopedJavaGlobalRef<jobject> java_object_; + + DISALLOW_COPY_AND_ASSIGN(AutofillExternalDelegateAndroid); +}; + +#endif // CHROME_BROWSER_UI_ANDROID_AUTOFILL_AUTOFILL_EXTERNAL_DELEGATE_H_ diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index f32ddf0..d365e6a 100644 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -2868,6 +2868,7 @@ 'target_name': 'chrome_browser_jni_headers', 'type': 'none', 'sources': [ + 'android/java/src/org/chromium/chrome/browser/autofill/AutofillExternalDelegate.java', 'android/java/src/org/chromium/chrome/browser/ChromeBrowserProvider.java', 'android/java/src/org/chromium/chrome/browser/ChromeHttpAuthHandler.java', 'android/java/src/org/chromium/chrome/browser/ChromeWebContentsDelegateAndroid.java', diff --git a/chrome/chrome_browser_ui.gypi b/chrome/chrome_browser_ui.gypi index dc12997..21cab93 100644 --- a/chrome/chrome_browser_ui.gypi +++ b/chrome/chrome_browser_ui.gypi @@ -105,6 +105,8 @@ 'browser/ui/alternate_error_tab_observer.h', 'browser/ui/android/android_about_app_info.cc', 'browser/ui/android/android_about_app_info.h', + 'browser/ui/android/autofill/autofill_external_delegate.cc', + 'browser/ui/android/autofill/autofill_external_delegate.h', 'browser/ui/android/certificate_viewer_android.cc', 'browser/ui/android/chrome_http_auth_handler.cc', 'browser/ui/android/chrome_http_auth_handler.h', diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi index 38f3297..6d70aa9 100644 --- a/chrome/chrome_tests.gypi +++ b/chrome/chrome_tests.gypi @@ -88,7 +88,6 @@ 'browser/autofill/data_driven_test.h', 'browser/autofill/test_autofill_external_delegate.cc', 'browser/autofill/test_autofill_external_delegate.h', - 'browser/autofill/test_autofill_external_delegate_android.cc', 'browser/automation/mock_tab_event_observer.cc', 'browser/automation/mock_tab_event_observer.h', 'browser/chromeos/cros/mock_cert_library.cc', diff --git a/chrome/test/base/chrome_test_suite.cc b/chrome/test/base/chrome_test_suite.cc index 11e29f9..d6f6dff 100644 --- a/chrome/test/base/chrome_test_suite.cc +++ b/chrome/test/base/chrome_test_suite.cc @@ -33,6 +33,7 @@ #if defined(OS_ANDROID) #include "base/android/jni_android.h" +#include "chrome/browser/android/chrome_jni_registrar.h" #include "net/android/net_jni_registrar.h" #endif @@ -194,6 +195,7 @@ void ChromeTestSuite::Initialize() { #if defined(OS_ANDROID) // Register JNI bindings for android. net::android::RegisterJni(base::android::AttachCurrentThread()); + chrome::android::RegisterJni(base::android::AttachCurrentThread()); #endif chrome::RegisterPathProvider(); diff --git a/content/browser/android/content_view_core_impl.cc b/content/browser/android/content_view_core_impl.cc index 45c15ce..bd4137a 100644 --- a/content/browser/android/content_view_core_impl.cc +++ b/content/browser/android/content_view_core_impl.cc @@ -248,6 +248,14 @@ ScopedJavaLocalRef<jobject> ContentViewCoreImpl::GetJavaObject() { return java_ref_.get(env); } +ScopedJavaLocalRef<jobject> ContentViewCoreImpl::GetContainerViewDelegate() { + JNIEnv* env = AttachCurrentThread(); + ScopedJavaLocalRef<jobject> obj = java_ref_.get(env); + if (obj.is_null()) + return ScopedJavaLocalRef<jobject>(); + return Java_ContentViewCore_getContainerViewDelegate(env, obj.obj()); +} + void ContentViewCoreImpl::OnWebPreferencesUpdated() { JNIEnv* env = AttachCurrentThread(); ScopedJavaLocalRef<jobject> obj = java_ref_.get(env); diff --git a/content/browser/android/content_view_core_impl.h b/content/browser/android/content_view_core_impl.h index bbfc68f..ccc56af 100644 --- a/content/browser/android/content_view_core_impl.h +++ b/content/browser/android/content_view_core_impl.h @@ -44,6 +44,8 @@ class ContentViewCoreImpl : public ContentViewCore, // ContentViewCore implementation. virtual base::android::ScopedJavaLocalRef<jobject> GetJavaObject() OVERRIDE; + virtual base::android::ScopedJavaLocalRef<jobject> GetContainerViewDelegate() + OVERRIDE; virtual WebContents* GetWebContents() const OVERRIDE; virtual ui::WindowAndroid* GetWindowAndroid() OVERRIDE; virtual void LoadUrl(NavigationController::LoadURLParams& params) OVERRIDE; diff --git a/content/public/android/java/src/org/chromium/content/app/AppResource.java b/content/public/android/java/src/org/chromium/content/app/AppResource.java index 3a2d06e..9a260f8f 100644 --- a/content/public/android/java/src/org/chromium/content/app/AppResource.java +++ b/content/public/android/java/src/org/chromium/content/app/AppResource.java @@ -60,6 +60,12 @@ public class AppResource { /** Drawable resource for the link preview popup overlay. */ public static int DRAWABLE_LINK_PREVIEW_POPUP_OVERLAY; + /** Id of the autofill label. */ + public static int ID_AUTOFILL_LABEL; + + /** Id of the autofill name. */ + public static int ID_AUTOFILL_NAME; + /** Id of the date picker view. */ public static int ID_DATE_PICKER; @@ -93,6 +99,9 @@ public class AppResource { /** Id of the view containing the month and year pickers. */ public static int ID_MONTH_YEAR_PICKERS_CONTAINER; + /** Layout of the autofill popup. */ + public static int LAYOUT_AUTOFILL_TEXT; + /** Layout of the date/time picker dialog. */ public static int LAYOUT_DATE_TIME_PICKER_DIALOG; diff --git a/content/public/android/java/src/org/chromium/content/browser/ContainerViewDelegate.java b/content/public/android/java/src/org/chromium/content/browser/ContainerViewDelegate.java new file mode 100644 index 0000000..8417345 --- /dev/null +++ b/content/public/android/java/src/org/chromium/content/browser/ContainerViewDelegate.java @@ -0,0 +1,25 @@ +// Copyright (c) 2012 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.content.browser; + +import android.view.View; + +/** + * Interface to add and remove views from the implementing view. + */ +public interface ContainerViewDelegate { + + /** + * Add the view. + * @param view The view to be added. + */ + public void addViewToContainerView(View view); + + /** + * Remove the view if it is present, otherwise do nothing. + * @param view The view to be removed. + */ + public void removeViewFromContainerView(View view); +}
\ No newline at end of file diff --git a/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java b/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java index 5941d8d..0812b1a 100644 --- a/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java +++ b/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java @@ -304,6 +304,32 @@ public class ContentViewCore implements MotionEventDelegate { return mContainerView; } + /** + * Returns a delegate that can be used to add and remove views from the ContainerView. + * + * NOTE: Use with care, as not all ContentViewCore users setup their ContainerView in the same + * way. In particular, the Android WebView has limitations on what implementation details can + * be provided via a child view, as they are visible in the API and could introduce + * compatibility breaks with existing applications. If in doubt, contact the + * android_webview/OWNERS + * + * @return A ContainerViewDelegate that can be used to add and remove views. + */ + @CalledByNative + public ContainerViewDelegate getContainerViewDelegate() { + return new ContainerViewDelegate() { + @Override + public void addViewToContainerView(View view) { + mContainerView.addView(view); + } + + @Override + public void removeViewFromContainerView(View view) { + mContainerView.removeView(view); + } + }; + } + private ImeAdapter createImeAdapter(Context context) { return new ImeAdapter(context, getSelectionHandleController(), getInsertionHandleController(), diff --git a/content/public/browser/android/content_view_core.h b/content/public/browser/android/content_view_core.h index bce865f..7be47e9 100644 --- a/content/public/browser/android/content_view_core.h +++ b/content/public/browser/android/content_view_core.h @@ -32,6 +32,8 @@ class ContentViewCore { virtual WebContents* GetWebContents() const = 0; virtual base::android::ScopedJavaLocalRef<jobject> GetJavaObject() = 0; + virtual base::android::ScopedJavaLocalRef<jobject> GetContainerViewDelegate() + = 0; virtual ui::WindowAndroid* GetWindowAndroid() = 0; virtual void LoadUrl(NavigationController::LoadURLParams& params) = 0; virtual void OnWebPreferencesUpdated() = 0; |