blob: 335abae10c2d51ed2bd26609411c90a37227cc4f [file] [log] [blame]
// Copyright 2017 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/infobars/translate_compact_infobar.h"
#include <stddef.h>
#include <memory>
#include "base/android/jni_android.h"
#include "base/android/jni_array.h"
#include "base/android/jni_string.h"
#include "base/android/jni_weak_ref.h"
#include "chrome/browser/infobars/infobar_service.h"
#include "chrome/browser/translate/android/translate_utils.h"
#include "components/translate/core/browser/translate_infobar_delegate.h"
#include "components/variations/variations_associated_data.h"
#include "content/public/browser/browser_context.h"
#include "jni/TranslateCompactInfoBar_jni.h"
using base::android::JavaParamRef;
using base::android::ScopedJavaLocalRef;
// Default values for the finch parameters. (used when the corresponding finch
// parameter does not exist.)
const int kDefaultAutoAlwaysThreshold = 5;
const int kDefaultAutoNeverThreshold = 10;
const int kDefaultMaxNumberOfAutoAlways = 2;
const int kDefaultMaxNumberOfAutoNever = 2;
// Finch parameter names:
const char kTranslateAutoAlwaysThreshold[] = "translate_auto_always_threshold";
const char kTranslateAutoNeverThreshold[] = "translate_auto_never_threshold";
const char kTranslateMaxNumberOfAutoAlways[] =
"translate_max_number_of_auto_always";
const char kTranslateMaxNumberOfAutoNever[] =
"translate_max_number_of_auto_never";
const char kTranslateTabDefaultTextColor[] = "translate_tab_default_text_color";
// ChromeTranslateClient
// ----------------------------------------------------------
std::unique_ptr<infobars::InfoBar> ChromeTranslateClient::CreateInfoBar(
std::unique_ptr<translate::TranslateInfoBarDelegate> delegate) const {
return std::make_unique<TranslateCompactInfoBar>(std::move(delegate));
}
// TranslateInfoBar -----------------------------------------------------------
TranslateCompactInfoBar::TranslateCompactInfoBar(
std::unique_ptr<translate::TranslateInfoBarDelegate> delegate)
: InfoBarAndroid(std::move(delegate)), action_flags_(FLAG_NONE) {
GetDelegate()->SetObserver(this);
// Flip the translate bit if auto translate is enabled.
if (GetDelegate()->translate_step() == translate::TRANSLATE_STEP_TRANSLATING)
action_flags_ |= FLAG_TRANSLATE;
}
TranslateCompactInfoBar::~TranslateCompactInfoBar() {
GetDelegate()->SetObserver(nullptr);
}
ScopedJavaLocalRef<jobject> TranslateCompactInfoBar::CreateRenderInfoBar(
JNIEnv* env) {
translate::TranslateInfoBarDelegate* delegate = GetDelegate();
base::android::ScopedJavaLocalRef<jobjectArray> java_languages =
TranslateUtils::GetJavaLanguages(env, delegate);
base::android::ScopedJavaLocalRef<jobjectArray> java_codes =
TranslateUtils::GetJavaLanguageCodes(env, delegate);
base::android::ScopedJavaLocalRef<jintArray> java_hash_codes =
TranslateUtils::GetJavaLanguageHashCodes(env, delegate);
ScopedJavaLocalRef<jstring> source_language_code =
base::android::ConvertUTF8ToJavaString(
env, delegate->original_language_code());
ScopedJavaLocalRef<jstring> target_language_code =
base::android::ConvertUTF8ToJavaString(env,
delegate->target_language_code());
return Java_TranslateCompactInfoBar_create(
env, delegate->translate_step(), source_language_code,
target_language_code, delegate->ShouldAlwaysTranslate(),
delegate->triggered_from_menu(), java_languages, java_codes,
java_hash_codes, TabDefaultTextColor());
}
void TranslateCompactInfoBar::ProcessButton(int action) {
if (!owner())
return; // We're closing; don't call anything, it might access the owner.
translate::TranslateInfoBarDelegate* delegate = GetDelegate();
if (action == InfoBarAndroid::ACTION_TRANSLATE) {
action_flags_ |= FLAG_TRANSLATE;
delegate->Translate();
if (!delegate->ShouldAlwaysTranslate() && ShouldAutoAlwaysTranslate()) {
JNIEnv* env = base::android::AttachCurrentThread();
Java_TranslateCompactInfoBar_setAutoAlwaysTranslate(env,
GetJavaInfoBar());
// Auto-always is triggered by the line above. Need to increment the
// auto-always counter.
delegate->IncrementTranslationAutoAlwaysCount();
// Reset translateAcceptedCount so that auto-always could be triggered
// again.
delegate->ResetTranslationAcceptedCount();
}
} else if (action == InfoBarAndroid::ACTION_TRANSLATE_SHOW_ORIGINAL) {
action_flags_ |= FLAG_REVERT;
delegate->RevertWithoutClosingInfobar();
} else {
DCHECK_EQ(InfoBarAndroid::ACTION_NONE, action);
}
}
void TranslateCompactInfoBar::SetJavaInfoBar(
const base::android::JavaRef<jobject>& java_info_bar) {
InfoBarAndroid::SetJavaInfoBar(java_info_bar);
JNIEnv* env = base::android::AttachCurrentThread();
Java_TranslateCompactInfoBar_setNativePtr(env, java_info_bar,
reinterpret_cast<intptr_t>(this));
}
void TranslateCompactInfoBar::ApplyStringTranslateOption(
JNIEnv* env,
const JavaParamRef<jobject>& obj,
int option,
const JavaParamRef<jstring>& value) {
translate::TranslateInfoBarDelegate* delegate = GetDelegate();
if (option == TranslateUtils::OPTION_SOURCE_CODE) {
std::string source_code =
base::android::ConvertJavaStringToUTF8(env, value);
if (delegate->original_language_code().compare(source_code) != 0)
delegate->UpdateOriginalLanguage(source_code);
} else if (option == TranslateUtils::OPTION_TARGET_CODE) {
std::string target_code =
base::android::ConvertJavaStringToUTF8(env, value);
if (delegate->target_language_code().compare(target_code) != 0)
delegate->UpdateTargetLanguage(target_code);
} else {
DCHECK(false);
}
}
void TranslateCompactInfoBar::ApplyBoolTranslateOption(
JNIEnv* env,
const JavaParamRef<jobject>& obj,
int option,
jboolean value) {
translate::TranslateInfoBarDelegate* delegate = GetDelegate();
if (option == TranslateUtils::OPTION_ALWAYS_TRANSLATE) {
if (delegate->ShouldAlwaysTranslate() != value) {
action_flags_ |= FLAG_ALWAYS_TRANSLATE;
delegate->ToggleAlwaysTranslate();
}
} else if (option == TranslateUtils::OPTION_NEVER_TRANSLATE) {
if (value && delegate->IsTranslatableLanguageByPrefs()) {
action_flags_ |= FLAG_NEVER_LANGUAGE;
delegate->ToggleTranslatableLanguageByPrefs();
RemoveSelf();
}
} else if (option == TranslateUtils::OPTION_NEVER_TRANSLATE_SITE) {
if (value && !delegate->IsSiteBlacklisted()) {
action_flags_ |= FLAG_NEVER_SITE;
delegate->ToggleSiteBlacklist();
RemoveSelf();
}
} else {
DCHECK(false);
}
}
bool TranslateCompactInfoBar::ShouldAutoAlwaysTranslate() {
translate::TranslateInfoBarDelegate* delegate = GetDelegate();
return (delegate->GetTranslationAcceptedCount() >= AutoAlwaysThreshold() &&
delegate->GetTranslationAutoAlwaysCount() < MaxNumberOfAutoAlways());
}
jboolean TranslateCompactInfoBar::ShouldAutoNeverTranslate(
JNIEnv* env,
const base::android::JavaParamRef<jobject>& obj,
jboolean menu_expanded) {
// Flip menu expanded bit.
if (menu_expanded)
action_flags_ |= FLAG_EXPAND_MENU;
if (!IsDeclinedByUser())
return false;
translate::TranslateInfoBarDelegate* delegate = GetDelegate();
// Don't trigger if it's off the record or already blocked.
if (delegate->is_off_the_record() ||
!delegate->IsTranslatableLanguageByPrefs())
return false;
int auto_never_count = delegate->GetTranslationAutoNeverCount();
// At the beginning (auto_never_count == 0), deniedCount starts at 0 and is
// off-by-one (because this checking is done before increment). However, after
// auto-never is triggered once (auto_never_count > 0), deniedCount starts at
// 1. So there is no off-by-one by then.
int off_by_one = auto_never_count == 0 ? 1 : 0;
bool never_translate = (delegate->GetTranslationDeniedCount() + off_by_one >=
AutoNeverThreshold() &&
auto_never_count < MaxNumberOfAutoNever());
if (never_translate) {
// Auto-never will be triggered. Need to increment the auto-never counter.
delegate->IncrementTranslationAutoNeverCount();
// Reset translateDeniedCount so that auto-never could be triggered again.
delegate->ResetTranslationDeniedCount();
}
return never_translate;
}
// Returns true if the current tab is an incognito tab.
jboolean TranslateCompactInfoBar::IsIncognito(
JNIEnv* env,
const base::android::JavaParamRef<jobject>& obj) {
content::WebContents* web_contents =
InfoBarService::WebContentsFromInfoBar(this);
if (!web_contents)
return false;
return web_contents->GetBrowserContext()->IsOffTheRecord();
}
int TranslateCompactInfoBar::GetParam(const std::string& paramName,
int default_value) {
std::map<std::string, std::string> params;
if (!variations::GetVariationParams(translate::kTranslateCompactUI.name,
&params))
return default_value;
int value = 0;
base::StringToInt(params[paramName], &value);
return value <= 0 ? default_value : value;
}
int TranslateCompactInfoBar::AutoAlwaysThreshold() {
return GetParam(kTranslateAutoAlwaysThreshold, kDefaultAutoAlwaysThreshold);
}
int TranslateCompactInfoBar::AutoNeverThreshold() {
return GetParam(kTranslateAutoNeverThreshold, kDefaultAutoNeverThreshold);
}
int TranslateCompactInfoBar::MaxNumberOfAutoAlways() {
return GetParam(kTranslateMaxNumberOfAutoAlways,
kDefaultMaxNumberOfAutoAlways);
}
int TranslateCompactInfoBar::MaxNumberOfAutoNever() {
return GetParam(kTranslateMaxNumberOfAutoNever, kDefaultMaxNumberOfAutoNever);
}
int TranslateCompactInfoBar::TabDefaultTextColor() {
return GetParam(kTranslateTabDefaultTextColor, 0);
}
translate::TranslateInfoBarDelegate* TranslateCompactInfoBar::GetDelegate() {
return delegate()->AsTranslateInfoBarDelegate();
}
void TranslateCompactInfoBar::OnTranslateStepChanged(
translate::TranslateStep step,
translate::TranslateErrors::Type error_type) {
if (!owner())
return; // We're closing; don't call anything.
if ((step == translate::TRANSLATE_STEP_AFTER_TRANSLATE) ||
(step == translate::TRANSLATE_STEP_TRANSLATE_ERROR)) {
JNIEnv* env = base::android::AttachCurrentThread();
Java_TranslateCompactInfoBar_onPageTranslated(env, GetJavaInfoBar(),
error_type);
}
}
bool TranslateCompactInfoBar::IsDeclinedByUser() {
// Whether there is any affirmative action bit.
return action_flags_ == FLAG_NONE;
}