// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/browser/sms/sms_provider_gms.h"
#include <string>
#include "base/android/scoped_java_ref.h"
#include "base/command_line.h"
#include "base/functional/bind.h"
#include "content/public/common/content_features.h"
#include "content/public/common/content_switches.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/web_contents.h"
#include "ui/android/window_android.h"
// Must come after all headers that specialize FromJniType() / ToJniType().
#include "content/public/android/content_jni_headers/SmsProviderGms_jni.h"
using base::android::AttachCurrentThread;
using base::android::ConvertJavaStringToUTF8;
namespace content {
SmsProviderGms::SmsProviderGms() {
// The backend depends on |features::kWebOtpBackendAuto| which is controlled
// by both a Finch experiment and chrome://flags. If the feature is enabled,
// the "Auto" backend will be used. If not, for backward compatibility we use
// the "UserConsent" backend. Note: in case of any conflict between finch and
// chrome flags, the latter takes precedence.
GmsBackend backend =
base::FeatureList::IsEnabled(features::kWebOtpBackendAuto)
? GmsBackend::kAuto
: GmsBackend::kUserConsent;
auto switch_value =
base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
switches::kWebOtpBackend);
if (switch_value == switches::kWebOtpBackendUserConsent) {
backend = GmsBackend::kUserConsent;
} else if (switch_value == switches::kWebOtpBackendSmsVerification) {
backend = GmsBackend::kVerification;
} else if (switch_value == switches::kWebOtpBackendAuto) {
backend = GmsBackend::kAuto;
}
// This class is constructed a single time whenever the first web page uses
// the SMS Retriever API to wait for SMSes.
JNIEnv* env = AttachCurrentThread();
j_sms_provider_.Reset(Java_SmsProviderGms_create(
env, reinterpret_cast<intptr_t>(this), static_cast<int>(backend)));
}
SmsProviderGms::~SmsProviderGms() {
JNIEnv* env = AttachCurrentThread();
Java_SmsProviderGms_destroy(env, j_sms_provider_);
}
void SmsProviderGms::Retrieve(RenderFrameHost* render_frame_host,
SmsFetchType fetch_type) {
// This function cannot get called during prerendering because
// SmsFetcherImpl::Subscribe calls this, and that is deferred during
// prerendering by MojoBinderPolicyApplier. This DCHECK proves we don't have
// to worry about prerendering when using WebContents::FromRenderFrameHost()
// below (see function comments for WebContents::FromRenderFrameHost() for
// more details).
DCHECK(!render_frame_host ||
(render_frame_host->GetLifecycleState() !=
RenderFrameHost::LifecycleState::kPrerendering));
WebContents* web_contents =
WebContents::FromRenderFrameHost(render_frame_host);
base::android::ScopedJavaLocalRef<jobject> j_window = nullptr;
if (web_contents && web_contents->GetTopLevelNativeWindow()) {
j_window = web_contents->GetTopLevelNativeWindow()->GetJavaObject();
}
JNIEnv* env = AttachCurrentThread();
Java_SmsProviderGms_listen(env, j_sms_provider_, j_window,
fetch_type == SmsFetchType::kLocal);
}
void SmsProviderGms::OnReceive(JNIEnv* env, jstring message, jint backend) {
GmsBackend b = static_cast<GmsBackend>(backend);
auto consent_requirement = UserConsent::kNotObtained;
if (b == GmsBackend::kUserConsent)
consent_requirement = UserConsent::kObtained;
std::string sms = ConvertJavaStringToUTF8(env, message);
NotifyReceive(sms, consent_requirement);
}
void SmsProviderGms::OnTimeout(JNIEnv* env) {
NotifyFailure(SmsFetchFailureType::kPromptTimeout);
}
void SmsProviderGms::OnCancel(JNIEnv* env) {
NotifyFailure(SmsFetchFailureType::kPromptCancelled);
}
void SmsProviderGms::OnNotAvailable(JNIEnv* env) {
NotifyFailure(SmsFetchFailureType::kBackendNotAvailable);
}
void SmsProviderGms::SetClientAndWindowForTesting(
const base::android::JavaRef<jobject>& j_fake_client,
const base::android::JavaRef<jobject>& j_window) {
JNIEnv* env = AttachCurrentThread();
Java_SmsProviderGms_setClientAndWindow(env, j_sms_provider_, j_fake_client,
j_window);
}
} // namespace content