chromium/chrome/browser/touch_to_fill/password_manager/no_passkeys/android/no_passkeys_bottom_sheet_bridge.cc

// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/touch_to_fill/password_manager/no_passkeys/android/no_passkeys_bottom_sheet_bridge.h"

#include "base/android/jni_string.h"
#include "ui/android/window_android.h"

// Must come after all headers that specialize FromJniType() / ToJniType().
#include "chrome/browser/touch_to_fill/password_manager/no_passkeys/internal/android/jni/NoPasskeysBottomSheetBridge_jni.h"

namespace {

using JniDelegate = NoPasskeysBottomSheetBridge::JniDelegate;

class JniDelegateImpl : public JniDelegate {
 public:
  explicit JniDelegateImpl(NoPasskeysBottomSheetBridge* bridge)
      : bridge_(bridge) {}
  JniDelegateImpl(const JniDelegateImpl&) = delete;
  JniDelegateImpl& operator=(const JniDelegateImpl&) = delete;
  ~JniDelegateImpl() override = default;

  void Create(ui::WindowAndroid* window_android) override {
    java_object_.Reset(Java_NoPasskeysBottomSheetBridge_Constructor(
        jni_zero::AttachCurrentThread(),
        reinterpret_cast<intptr_t>(bridge_.get()),
        window_android->GetJavaObject()));
  }

  void Show(const std::string& origin) override {
    JNIEnv* env = jni_zero::AttachCurrentThread();
    Java_NoPasskeysBottomSheetBridge_show(
        env, java_object_, base::android::ConvertUTF8ToJavaString(env, origin));
  }

  void Dismiss() override {
    Java_NoPasskeysBottomSheetBridge_dismiss(jni_zero::AttachCurrentThread(),
                                             java_object_);
  }

 private:
  // The corresponding Java NoPasskeysBottomSheetBridge.
  base::android::ScopedJavaGlobalRef<jobject> java_object_;
  // The owning native NoPasskeysBottomSheetBridge.
  raw_ptr<NoPasskeysBottomSheetBridge> bridge_;
};

}  // namespace

NoPasskeysBottomSheetBridge::JniDelegate::JniDelegate() = default;
NoPasskeysBottomSheetBridge::JniDelegate::~JniDelegate() = default;

NoPasskeysBottomSheetBridge::NoPasskeysBottomSheetBridge()
    : jni_delegate_(std::make_unique<JniDelegateImpl>(this)) {}

NoPasskeysBottomSheetBridge::NoPasskeysBottomSheetBridge(
    base::PassKey<class NoPasskeysBottomSheetBridgeTest>,
    std::unique_ptr<JniDelegate> jni_delegate)
    : jni_delegate_(std::move(jni_delegate)) {}

NoPasskeysBottomSheetBridge::NoPasskeysBottomSheetBridge(
    base::PassKey<class TouchToFillControllerWebAuthnTest>,
    std::unique_ptr<JniDelegate> jni_delegate)
    : jni_delegate_(std::move(jni_delegate)) {}

NoPasskeysBottomSheetBridge::~NoPasskeysBottomSheetBridge() {
  Dismiss();
}

void NoPasskeysBottomSheetBridge::Show(
    ui::WindowAndroid* window_android,
    const std::string& origin,
    base::OnceClosure on_dismissed_callback,
    base::OnceClosure on_click_use_another_device_callback) {
  CHECK(window_android) << "The bridge needs a window to attach to!";
  CHECK(on_dismissed_callback) << "The bridge needs a clean up callback!";
  CHECK(!on_dismissed_callback_)
      << "Show was already called. Use each bridge only once.";

  on_dismissed_callback_ = std::move(on_dismissed_callback);
  on_click_use_another_device_callback_ =
      std::move(on_click_use_another_device_callback);
  jni_delegate_->Create(window_android);
  jni_delegate_->Show(origin);
}

void NoPasskeysBottomSheetBridge::Dismiss() {
  if (on_dismissed_callback_) {  // Not dismissed yet.
    jni_delegate_->Dismiss();
  }
}

void NoPasskeysBottomSheetBridge::OnDismissed(JNIEnv* env) {
  CHECK(on_dismissed_callback_);
  std::move(on_dismissed_callback_).Run();
}

void NoPasskeysBottomSheetBridge::OnClickUseAnotherDevice(JNIEnv* env) {
  CHECK(on_click_use_another_device_callback_);
  std::move(on_click_use_another_device_callback_).Run();
}