blob: 016df3851fc0e93cb4516b1d2d6ebf055bce02bf [file] [log] [blame]
// Copyright 2018 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/android/password_manager/manual_filling_view_android.h"
#include <jni.h>
#include <map>
#include <memory>
#include <string>
#include <vector>
#include "base/android/callback_android.h"
#include "base/android/jni_android.h"
#include "base/android/jni_array.h"
#include "base/android/jni_string.h"
#include "base/bind.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/autofill/manual_filling_controller.h"
#include "chrome/browser/autofill/manual_filling_controller_impl.h"
#include "chrome/browser/password_manager/password_accessory_controller.h"
#include "components/autofill/core/browser/accessory_sheet_data.h"
#include "components/autofill/core/common/password_form.h"
#include "jni/ManualFillingBridge_jni.h"
#include "ui/android/view_android.h"
#include "ui/android/window_android.h"
#include "ui/gfx/android/java_bitmap.h"
#include "ui/gfx/image/image.h"
using autofill::AccessorySheetData;
using autofill::FooterCommand;
using autofill::UserInfo;
using base::android::ConvertUTF16ToJavaString;
using base::android::ScopedJavaLocalRef;
ManualFillingViewAndroid::ManualFillingViewAndroid(
ManualFillingController* controller)
: controller_(controller) {
ui::ViewAndroid* view_android = controller_->container_view();
DCHECK(view_android);
java_object_.Reset(Java_ManualFillingBridge_create(
base::android::AttachCurrentThread(), reinterpret_cast<intptr_t>(this),
view_android->GetWindowAndroid()->GetJavaObject()));
}
ManualFillingViewAndroid::~ManualFillingViewAndroid() {
DCHECK(!java_object_.is_null());
Java_ManualFillingBridge_destroy(base::android::AttachCurrentThread(),
java_object_);
java_object_.Reset(nullptr);
}
void ManualFillingViewAndroid::OnItemsAvailable(
const AccessorySheetData& data) {
DCHECK(!java_object_.is_null());
JNIEnv* env = base::android::AttachCurrentThread();
Java_ManualFillingBridge_onItemsAvailable(
env, java_object_, ConvertAccessorySheetDataToJavaObject(env, data));
}
void ManualFillingViewAndroid::CloseAccessorySheet() {
Java_ManualFillingBridge_closeAccessorySheet(
base::android::AttachCurrentThread(), java_object_);
}
void ManualFillingViewAndroid::SwapSheetWithKeyboard() {
Java_ManualFillingBridge_swapSheetWithKeyboard(
base::android::AttachCurrentThread(), java_object_);
}
void ManualFillingViewAndroid::ShowWhenKeyboardIsVisible() {
Java_ManualFillingBridge_showWhenKeyboardIsVisible(
base::android::AttachCurrentThread(), java_object_);
}
void ManualFillingViewAndroid::Hide() {
Java_ManualFillingBridge_hide(base::android::AttachCurrentThread(),
java_object_);
}
void ManualFillingViewAndroid::OnAutomaticGenerationStatusChanged(
bool available) {
if (!available && java_object_.is_null())
return;
JNIEnv* env = base::android::AttachCurrentThread();
Java_ManualFillingBridge_onAutomaticGenerationStatusChanged(env, java_object_,
available);
}
void ManualFillingViewAndroid::OnFaviconRequested(
JNIEnv* env,
const base::android::JavaParamRef<jobject>& obj,
jint desiredSizeInPx,
const base::android::JavaParamRef<jobject>& j_callback) {
controller_->GetFavicon(
desiredSizeInPx,
base::BindOnce(&ManualFillingViewAndroid::OnImageFetched,
base::Unretained(this), // Outlives or cancels request.
base::android::ScopedJavaGlobalRef<jobject>(j_callback)));
}
void ManualFillingViewAndroid::OnFillingTriggered(
JNIEnv* env,
const base::android::JavaParamRef<jobject>& obj,
jboolean isPassword,
const base::android::JavaParamRef<_jstring*>& textToFill) {
controller_->OnFillingTriggered(
isPassword, base::android::ConvertJavaStringToUTF16(textToFill));
}
void ManualFillingViewAndroid::OnOptionSelected(
JNIEnv* env,
const base::android::JavaParamRef<jobject>& obj,
const base::android::JavaParamRef<_jstring*>& selectedOption) {
controller_->OnOptionSelected(
base::android::ConvertJavaStringToUTF16(selectedOption));
}
void ManualFillingViewAndroid::OnGenerationRequested(
JNIEnv* env,
const base::android::JavaParamRef<jobject>& obj) {
controller_->OnGenerationRequested();
}
void ManualFillingViewAndroid::OnImageFetched(
const base::android::ScopedJavaGlobalRef<jobject>& j_callback,
const gfx::Image& image) {
base::android::ScopedJavaLocalRef<jobject> j_bitmap;
if (!image.IsEmpty())
j_bitmap = gfx::ConvertToJavaBitmap(image.ToSkBitmap());
RunObjectCallbackAndroid(j_callback, j_bitmap);
}
ScopedJavaLocalRef<jobject>
ManualFillingViewAndroid::ConvertAccessorySheetDataToJavaObject(
JNIEnv* env,
const AccessorySheetData& tab_data) {
ScopedJavaLocalRef<jobject> j_tab_data =
Java_ManualFillingBridge_createAccessorySheetData(
env, ConvertUTF16ToJavaString(env, tab_data.title()));
for (const UserInfo& user_info : tab_data.user_info_list()) {
ScopedJavaLocalRef<jobject> j_user_info =
Java_ManualFillingBridge_addUserInfoToAccessorySheetData(
env, java_object_, j_tab_data);
for (const UserInfo::Field& field : user_info.fields()) {
Java_ManualFillingBridge_addFieldToUserInfo(
env, java_object_, j_user_info,
ConvertUTF16ToJavaString(env, field.display_text()),
ConvertUTF16ToJavaString(env, field.a11y_description()),
field.is_obfuscated(), field.selectable());
}
}
for (const FooterCommand& footer_command : tab_data.footer_commands()) {
Java_ManualFillingBridge_addFooterCommandToAccessorySheetData(
env, java_object_, j_tab_data,
ConvertUTF16ToJavaString(env, footer_command.display_text()));
}
return j_tab_data;
}
// static
void JNI_ManualFillingBridge_CachePasswordSheetDataForTesting(
JNIEnv* env,
const base::android::JavaParamRef<jobject>& j_web_contents,
const base::android::JavaParamRef<jobjectArray>& j_usernames,
const base::android::JavaParamRef<jobjectArray>& j_passwords) {
content::WebContents* web_contents =
content::WebContents::FromJavaWebContents(j_web_contents);
PasswordAccessoryController* pwd_controller =
static_cast<ManualFillingControllerImpl*>(
ManualFillingControllerImpl::GetOrCreate(web_contents).get())
->password_controller_for_testing();
if (!pwd_controller) {
// If the controller isn't initialized (e.g. because the flags are not set),
// fail silently so tests can use shared setup methods for old and new UI.
LOG(ERROR) << "Tried to fill cache of non-existent accessory controller.";
return;
}
url::Origin origin = url::Origin::Create(web_contents->GetLastCommittedURL());
std::vector<std::string> usernames;
std::vector<std::string> passwords;
base::android::AppendJavaStringArrayToStringVector(env, j_usernames,
&usernames);
base::android::AppendJavaStringArrayToStringVector(env, j_passwords,
&passwords);
std::vector<autofill::PasswordForm> password_forms(usernames.size());
std::map<base::string16, const autofill::PasswordForm*> credentials;
for (unsigned int i = 0; i < usernames.size(); ++i) {
password_forms[i].origin = origin.GetURL();
password_forms[i].username_value = base::ASCIIToUTF16(usernames[i]);
password_forms[i].password_value = base::ASCIIToUTF16(passwords[i]);
credentials[password_forms[i].username_value] = &password_forms[i];
}
pwd_controller->SavePasswordsForOrigin(credentials, origin);
}
// static
std::unique_ptr<ManualFillingViewInterface> ManualFillingViewInterface::Create(
ManualFillingController* controller) {
return std::make_unique<ManualFillingViewAndroid>(controller);
}