Adds mojo interface to interact with AI credential manager from Java

This commit is contained in:
Serg
2023-12-15 07:30:33 -05:00
parent f041b282de
commit fe838418e6
13 changed files with 287 additions and 1 deletions
+1
View File
@@ -77,6 +77,7 @@ brave_java_sources = [
"../../brave/android/java/org/chromium/chrome/browser/bookmarks/BraveBookmarkToolbarCoordinator.java",
"../../brave/android/java/org/chromium/chrome/browser/bookmarks/BraveBookmarkUtils.java",
"../../brave/android/java/org/chromium/chrome/browser/brave_leo/BraveLeoActivity.java",
"../../brave/android/java/org/chromium/chrome/browser/brave_leo/BraveLeoCMHelper.java",
"../../brave/android/java/org/chromium/chrome/browser/brave_leo/BraveLeoSettingsLauncherHelper.java",
"../../brave/android/java/org/chromium/chrome/browser/brave_news/BraveNewsAdapterFeedCard.java",
"../../brave/android/java/org/chromium/chrome/browser/brave_news/BraveNewsBottomSheetDialogFragment.java",
@@ -0,0 +1,82 @@
/* Copyright (c) 2023 The Brave Authors. All rights reserved.
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at https://mozilla.org/MPL/2.0/. */
package org.chromium.chrome.browser.brave_leo;
import org.chromium.ai_chat.mojom.CredentialManagerHelper;
import org.chromium.base.annotations.JNINamespace;
import org.chromium.base.annotations.NativeMethods;
import org.chromium.content_public.browser.BrowserContextHandle;
import org.chromium.mojo.bindings.ConnectionErrorHandler;
import org.chromium.mojo.bindings.Interface;
import org.chromium.mojo.bindings.Interface.Proxy.Handler;
import org.chromium.mojo.system.MessagePipeHandle;
import org.chromium.mojo.system.MojoException;
import org.chromium.mojo.system.impl.CoreImpl;
/** Helper to interact with ai_chat_credential_manager. */
@JNINamespace("ai_chat")
public class BraveLeoCMHelper implements ConnectionErrorHandler {
private long mNativeAIChatCMHelperAndroid;
CredentialManagerHelper mCredentialManagerHelper;
private static final Object sLock = new Object();
private static BraveLeoCMHelper sInstance;
public static BraveLeoCMHelper getInstance(BrowserContextHandle browserContextHandle) {
synchronized (sLock) {
if (sInstance == null) {
sInstance = new BraveLeoCMHelper(browserContextHandle);
}
}
return sInstance;
}
private BraveLeoCMHelper(BrowserContextHandle browserContextHandle) {
mNativeAIChatCMHelperAndroid = BraveLeoCMHelperJni.get().init(browserContextHandle);
long nativeHandle =
BraveLeoCMHelperJni.get()
.getInterfaceToCredentialManagerHelper(mNativeAIChatCMHelperAndroid);
MessagePipeHandle handle =
CoreImpl.getInstance().acquireNativeHandle(nativeHandle).toMessagePipeHandle();
mCredentialManagerHelper = CredentialManagerHelper.MANAGER.attachProxy(handle, 0);
Handler handler = ((Interface.Proxy) mCredentialManagerHelper).getProxyHandler();
handler.setErrorHandler(this);
}
public void destroy() {
synchronized (sLock) {
sInstance = null;
if (mNativeAIChatCMHelperAndroid == 0 && mCredentialManagerHelper == null) {
return;
}
mCredentialManagerHelper.close();
mCredentialManagerHelper = null;
BraveLeoCMHelperJni.get().destroy(mNativeAIChatCMHelperAndroid);
mNativeAIChatCMHelperAndroid = 0;
}
}
public void getPremiumStatus(CredentialManagerHelper.GetPremiumStatus_Response callback) {
if (mCredentialManagerHelper == null) {
return;
}
mCredentialManagerHelper.getPremiumStatus(callback);
}
@Override
public void onConnectionError(MojoException e) {
destroy();
}
@NativeMethods
public interface Natives {
long init(BrowserContextHandle browserContextHandle);
void destroy(long nativeAIChatCMHelperAndroid);
long getInterfaceToCredentialManagerHelper(long nativeAIChatCMHelperAndroid);
}
}
@@ -7,14 +7,61 @@ package org.chromium.chrome.browser.settings;
import android.os.Bundle;
import org.chromium.ai_chat.mojom.PremiumStatus;
import org.chromium.base.Log;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.app.BraveActivity;
import org.chromium.chrome.browser.brave_leo.BraveLeoCMHelper;
import org.chromium.chrome.browser.util.TabUtils;
import org.chromium.components.browser_ui.settings.ChromeBasePreference;
import org.chromium.components.browser_ui.settings.SettingsUtils;
public class BraveLeoPreferences extends BravePreferenceFragment {
private static final String TAG = "BraveLeoPreferences";
private static final String PREF_LINK_SUBSCRIPTION = "link_subscription";
private static final String LINK_SUBSCRIPTION_URL = "https://account.brave.com";
@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
requireActivity().setTitle(R.string.menu_brave_leo);
SettingsUtils.addPreferencesFromResource(this, R.xml.brave_leo_preferences);
BraveLeoCMHelper.getInstance(getProfile())
.getPremiumStatus(
status -> {
if (status != PremiumStatus.ACTIVE) {
ChromeBasePreference link_subscription =
findPreference(PREF_LINK_SUBSCRIPTION);
if (link_subscription == null) {
Log.e(TAG, "Subscription pref is null");
return;
}
link_subscription.setVisible(true);
link_subscription.setOnPreferenceClickListener(
preference -> {
try {
BraveActivity.getBraveActivity()
.openNewOrSelectExistingTab(
LINK_SUBSCRIPTION_URL, true);
TabUtils.bringChromeTabbedActivityToTheTop(
getActivity());
} catch (
BraveActivity.BraveActivityNotFoundException
e) {
Log.e(
TAG,
"Error while opening subscription tab.",
e);
}
return true;
});
}
});
}
@Override
public void onDestroyView() {
super.onDestroyView();
BraveLeoCMHelper.getInstance(getProfile()).destroy();
}
}
+11 -1
View File
@@ -4,11 +4,21 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. -->
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<org.chromium.chrome.browser.settings.BraveLeoDescriptionPreference
android:key="leo_summary"
android:summary="@string/leo_summary" />
<org.chromium.components.browser_ui.settings.ChromeBasePreference
android:key="link_subscription"
android:title="@string/link_subscription_title_leo"
android:summary="@string/link_subscription_summary_leo"
app:isPreferenceVisible="false"/>
<org.chromium.components.browser_ui.settings.ChromeBasePreference
android:key="subscription_manage"
android:title="@string/manage_subscription_leo"
app:isPreferenceVisible="false"/>
<org.chromium.chrome.browser.settings.BraveLeoResetPreference
android:key="reset_data"
android:title="@string/leo_reset_data"/>
@@ -0,0 +1,67 @@
/* Copyright (c) 2023 The Brave Authors. All rights reserved.
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at https://mozilla.org/MPL/2.0/. */
#include "brave/browser/ai_chat/android/ai_chat_cm_helper_android.h"
#include <utility>
#include "brave/browser/skus/skus_service_factory.h"
#include "brave/build/android/jni_headers/BraveLeoCMHelper_jni.h"
#include "chrome/browser/browser_process.h"
#include "content/public/browser/android/browser_context_handle.h"
#include "content/public/browser/browser_context.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
namespace ai_chat {
static jlong JNI_BraveLeoCMHelper_Init(
JNIEnv* env,
const base::android::JavaParamRef<jobject>& jbrowser_context_handle) {
AIChatCMHelperAndroid* cm_helper =
new AIChatCMHelperAndroid(jbrowser_context_handle);
return reinterpret_cast<intptr_t>(cm_helper);
}
AIChatCMHelperAndroid::AIChatCMHelperAndroid(
const base::android::JavaParamRef<jobject>& jbrowser_context_handle) {
content::BrowserContext* context =
content::BrowserContextFromJavaHandle(jbrowser_context_handle);
auto skus_service_getter = base::BindRepeating(
[](content::BrowserContext* context) {
return skus::SkusServiceFactory::GetForContext(context);
},
context);
credential_manager_ = std::make_unique<ai_chat::AIChatCredentialManager>(
skus_service_getter, g_browser_process->local_state());
}
AIChatCMHelperAndroid::~AIChatCMHelperAndroid() = default;
void AIChatCMHelperAndroid::Destroy(JNIEnv* env) {
delete this;
}
jlong AIChatCMHelperAndroid::GetInterfaceToCredentialManagerHelper(
JNIEnv* env) {
mojo::PendingRemote<mojom::CredentialManagerHelper> remote;
receivers_.Add(this, remote.InitWithNewPipeAndPassReceiver());
return static_cast<jlong>(remote.PassPipe().release().value());
}
void AIChatCMHelperAndroid::GetPremiumStatus(
GetPremiumStatusCallback callback) {
credential_manager_->GetPremiumStatus(
base::BindOnce(&AIChatCMHelperAndroid::OnPremiumStatusReceived,
weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
}
void AIChatCMHelperAndroid::OnPremiumStatusReceived(
mojom::PageHandler::GetPremiumStatusCallback parent_callback,
mojom::PremiumStatus premium_status) {
std::move(parent_callback).Run(premium_status);
}
} // namespace ai_chat
@@ -0,0 +1,42 @@
/* Copyright (c) 2023 The Brave Authors. All rights reserved.
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at https://mozilla.org/MPL/2.0/. */
#ifndef BRAVE_BROWSER_AI_CHAT_ANDROID_AI_CHAT_CM_HELPER_ANDROID_H_
#define BRAVE_BROWSER_AI_CHAT_ANDROID_AI_CHAT_CM_HELPER_ANDROID_H_
#include <memory>
#include "base/android/jni_android.h"
#include "base/android/scoped_java_ref.h"
#include "base/memory/raw_ptr.h"
#include "brave/components/ai_chat/core/browser/ai_chat_credential_manager.h"
#include "brave/components/ai_chat/core/common/mojom/ai_chat.mojom.h"
#include "mojo/public/cpp/bindings/receiver_set.h"
namespace ai_chat {
class AIChatCMHelperAndroid : public mojom::CredentialManagerHelper {
public:
AIChatCMHelperAndroid(
const base::android::JavaParamRef<jobject>& jbrowser_context_handle);
~AIChatCMHelperAndroid() override;
void Destroy(JNIEnv* env);
void GetPremiumStatus(GetPremiumStatusCallback callback) override;
jlong GetInterfaceToCredentialManagerHelper(JNIEnv* env);
private:
void OnPremiumStatusReceived(
mojom::PageHandler::GetPremiumStatusCallback parent_callback,
mojom::PremiumStatus premium_status);
std::unique_ptr<AIChatCredentialManager> credential_manager_;
mojo::ReceiverSet<mojom::CredentialManagerHelper> receivers_;
base::WeakPtrFactory<AIChatCMHelperAndroid> weak_ptr_factory_{this};
};
} // namespace ai_chat
#endif // BRAVE_BROWSER_AI_CHAT_ANDROID_AI_CHAT_CM_HELPER_ANDROID_H_
+14
View File
@@ -0,0 +1,14 @@
# Copyright (c) 2023 The Brave Authors. All rights reserved.
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
# You can obtain one at https://mozilla.org/MPL/2.0/.
brave_browser_ai_chat_android_sources = [
"//brave/browser/ai_chat/android/ai_chat_cm_helper_android.cc",
"//brave/browser/ai_chat/android/ai_chat_cm_helper_android.h",
]
brave_browser_ai_chat_android_deps = [
"//brave/components/ai_chat/core/browser",
"//brave/components/ai_chat/core/common/mojom",
]
+6
View File
@@ -3,6 +3,7 @@
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
# You can obtain one at http://mozilla.org/MPL/2.0/.
import("//brave/browser/ai_chat/android/sources.gni")
import("//brave/browser/autocomplete/sources.gni")
import("//brave/browser/brave_adaptive_captcha/sources.gni")
import("//brave/browser/brave_ads/sources.gni")
@@ -292,6 +293,11 @@ if (enable_ai_chat) {
"//brave/components/ai_chat/core/common",
"//brave/components/ai_chat/core/common/mojom",
]
if (is_android) {
brave_chrome_browser_sources += brave_browser_ai_chat_android_sources
brave_chrome_browser_deps += brave_browser_ai_chat_android_deps
}
}
if (enable_brave_vpn) {
@@ -4100,6 +4100,15 @@ If you don't accept this request, VPN will not reconnect and your internet conne
<message name="IDS_ELLIPSIS_TEXT" desc="Generic ellipsis text" translateable="false">
...
</message>
<message name="IDS_LINK_SUBSCRIPTION_TITLE_LEO" desc="Brave Leo link subscription settings title text">
Link purchase to your Brave account
</message>
<message name="IDS_LINK_SUBSCRIPTION_SUMMARY_LEO" desc="Brave Leo link subscription settings summary">
Link your Play Store purchase to your Brave account to use Brave Leo on other devices.
</message>
<message name="IDS_MANAGE_SUBSCRIPTION_LEO" desc="Brave Leo settings section text">
Manage Subscription
</message>
</messages>
</release>
</grit>
+1
View File
@@ -212,6 +212,7 @@ generate_jni("jni_headers") {
"//brave/android/java/org/chromium/chrome/browser/BraveSyncWorker.java",
"//brave/android/java/org/chromium/chrome/browser/app/BraveActivity.java",
"//brave/android/java/org/chromium/chrome/browser/bookmarks/BraveBookmarkBridge.java",
"//brave/android/java/org/chromium/chrome/browser/brave_leo/BraveLeoCMHelper.java",
"//brave/android/java/org/chromium/chrome/browser/brave_leo/BraveLeoSettingsLauncherHelper.java",
"//brave/android/java/org/chromium/chrome/browser/brave_news/BraveNewsControllerFactory.java",
"//brave/android/java/org/chromium/chrome/browser/crypto_wallet/AssetRatioServiceFactory.java",
+2
View File
@@ -30,6 +30,7 @@ brave_chrome_java_deps = [
"//brave/browser/ui/android/logo:java",
"//brave/browser/ui/android/omnibox:java",
"//brave/browser/ui/android/theme:java",
"//brave/components/ai_chat/core/common/mojom:mojom_java",
"//brave/components/brave_news/common:mojom_java",
"//brave/components/brave_rewards/common/mojom:mojom_java",
"//brave/components/brave_shields/common:mojom_java",
@@ -110,6 +111,7 @@ brave_jni_headers_sources = [
"//brave/android/java/org/chromium/chrome/browser/BraveSyncWorker.java",
"//brave/android/java/org/chromium/chrome/browser/app/BraveActivity.java",
"//brave/android/java/org/chromium/chrome/browser/bookmarks/BraveBookmarkBridge.java",
"//brave/android/java/org/chromium/chrome/browser/brave_leo/BraveLeoCMHelper.java",
"//brave/android/java/org/chromium/chrome/browser/brave_news/BraveNewsControllerFactory.java",
"//brave/android/java/org/chromium/chrome/browser/crypto_wallet/AssetRatioServiceFactory.java",
"//brave/android/java/org/chromium/chrome/browser/crypto_wallet/BlockchainRegistryFactory.java",
@@ -6,6 +6,7 @@
import("//mojo/public/tools/bindings/mojom.gni")
mojom("mojom") {
generate_java = true
sources = [
"ai_chat.mojom",
"page_content_extractor.mojom",
@@ -159,3 +159,7 @@ interface ChatUIPage {
// This reports if there are any pending entries to be sent to the remote LLM.
OnConversationEntryPending();
};
interface CredentialManagerHelper {
GetPremiumStatus() => (PremiumStatus result);
};