Adds preference on Android to select default Leo model

This commit is contained in:
Serg
2024-02-05 12:07:34 -05:00
parent c6862cae21
commit 8df8eebc00
24 changed files with 529 additions and 250 deletions
+2
View File
@@ -1019,7 +1019,9 @@ brave_java_resources = [
"java/res/xml/background_images_preferences.xml",
"java/res/xml/brave_download_preferences.xml",
"java/res/xml/brave_ethereum_preferences.xml",
"java/res/xml/brave_leo_default_model_preferences.xml",
"java/res/xml/brave_leo_preferences.xml",
"java/res/xml/brave_leo_radio_button_group_default_model_preference.xml",
"java/res/xml/brave_license_preferences.xml",
"java/res/xml/brave_main_preferences.xml",
"java/res/xml/brave_playlist_preferences.xml",
+3 -2
View File
@@ -78,7 +78,7 @@ brave_java_sources = [
"../../brave/android/java/org/chromium/chrome/browser/bookmarks/BraveBookmarkUiPrefs.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/BraveLeoMojomHelper.java",
"../../brave/android/java/org/chromium/chrome/browser/brave_leo/BraveLeoPlansActivity.java",
"../../brave/android/java/org/chromium/chrome/browser/brave_leo/BraveLeoPrefUtils.java",
"../../brave/android/java/org/chromium/chrome/browser/brave_leo/BraveLeoSettingsLauncherHelper.java",
@@ -350,8 +350,9 @@ brave_java_sources = [
"../../brave/android/java/org/chromium/chrome/browser/settings/AppearancePreferences.java",
"../../brave/android/java/org/chromium/chrome/browser/settings/BackgroundImagesPreferences.java",
"../../brave/android/java/org/chromium/chrome/browser/settings/BraveDialogPreference.java",
"../../brave/android/java/org/chromium/chrome/browser/settings/BraveLeoDescriptionPreference.java",
"../../brave/android/java/org/chromium/chrome/browser/settings/BraveLeoDefaultModelPreferences.java",
"../../brave/android/java/org/chromium/chrome/browser/settings/BraveLeoPreferences.java",
"../../brave/android/java/org/chromium/chrome/browser/settings/BraveLeoRadioButtonGroupDefaultModelPreference.java",
"../../brave/android/java/org/chromium/chrome/browser/settings/BraveLeoResetPreference.java",
"../../brave/android/java/org/chromium/chrome/browser/settings/BraveLicensePreference.java",
"../../brave/android/java/org/chromium/chrome/browser/settings/BraveLicensePreferences.java",
@@ -41,6 +41,8 @@ import java.util.Locale;
import java.util.Map;
public class InAppPurchaseWrapper {
public static final String MANAGE_SUBSCRIPTION_PAGE =
"https://play.google.com/store/account/subscriptions";
private static final String TAG = "InAppPurchaseWrapper";
private static final String LEO_MONTHLY_SUBSCRIPTION = "brave.leo.monthly";
@@ -1,85 +0,0 @@
/* 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.jni_zero.JNINamespace;
import org.jni_zero.NativeMethods;
import org.chromium.ai_chat.mojom.CredentialManagerHelper;
import org.chromium.ai_chat.mojom.PremiumStatus;
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) {
callback.call(PremiumStatus.INACTIVE, 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);
}
}
@@ -0,0 +1,97 @@
/* 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.jni_zero.JNINamespace;
import org.jni_zero.NativeMethods;
import org.chromium.ai_chat.mojom.AiChatAndroidHelper;
import org.chromium.ai_chat.mojom.ModelWithSubtitle;
import org.chromium.ai_chat.mojom.PremiumStatus;
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 native AIChatMojomHelperAndroid. Check ai_chat_mojom_helper_android.h,
* ai_chat_mojom_helper_android.cc for native parts
*/
@JNINamespace("ai_chat")
public class BraveLeoMojomHelper implements ConnectionErrorHandler {
private long mNativeAIChatCMHelperAndroid;
AiChatAndroidHelper mAIChatAndroidHelper;
private static final Object sLock = new Object();
private static BraveLeoMojomHelper sInstance;
public static BraveLeoMojomHelper getInstance(BrowserContextHandle browserContextHandle) {
synchronized (sLock) {
if (sInstance == null) {
sInstance = new BraveLeoMojomHelper(browserContextHandle);
}
}
return sInstance;
}
private BraveLeoMojomHelper(BrowserContextHandle browserContextHandle) {
mNativeAIChatCMHelperAndroid = BraveLeoMojomHelperJni.get().init(browserContextHandle);
long nativeHandle =
BraveLeoMojomHelperJni.get()
.getInterfaceToAndroidHelper(mNativeAIChatCMHelperAndroid);
MessagePipeHandle handle =
CoreImpl.getInstance().acquireNativeHandle(nativeHandle).toMessagePipeHandle();
mAIChatAndroidHelper = AiChatAndroidHelper.MANAGER.attachProxy(handle, 0);
Handler handler = ((Interface.Proxy) mAIChatAndroidHelper).getProxyHandler();
handler.setErrorHandler(this);
}
public void destroy() {
synchronized (sLock) {
sInstance = null;
if (mNativeAIChatCMHelperAndroid == 0 && mAIChatAndroidHelper == null) {
return;
}
mAIChatAndroidHelper.close();
mAIChatAndroidHelper = null;
BraveLeoMojomHelperJni.get().destroy(mNativeAIChatCMHelperAndroid);
mNativeAIChatCMHelperAndroid = 0;
}
}
public void getPremiumStatus(AiChatAndroidHelper.GetPremiumStatus_Response callback) {
if (mAIChatAndroidHelper == null) {
callback.call(PremiumStatus.INACTIVE, null);
return;
}
mAIChatAndroidHelper.getPremiumStatus(callback);
}
public void getModels(AiChatAndroidHelper.GetModelsWithSubtitles_Response callback) {
if (mAIChatAndroidHelper == null) {
callback.call(new ModelWithSubtitle[0]);
return;
}
mAIChatAndroidHelper.getModelsWithSubtitles(callback);
}
@Override
public void onConnectionError(MojoException e) {
destroy();
}
@NativeMethods
public interface Natives {
long init(BrowserContextHandle browserContextHandle);
void destroy(long nativeAIChatMojomHelperAndroid);
long getInterfaceToAndroidHelper(long nativeAIChatMojomHelperAndroid);
}
}
@@ -79,4 +79,22 @@ public class BraveLeoPrefUtils {
}
UserPrefs.get(profileToUse).setString(BravePref.BRAVE_CHAT_PRODUCT_ID_ANDROID, productId);
}
public static String getDefaultModel() {
Profile profileToUse = BraveLeoPrefUtils.getProfile();
if (profileToUse == null) {
Log.e(TAG, "BraveLeoPrefUtils.getDefaultModel profile is null");
return "";
}
return UserPrefs.get(profileToUse).getString(BravePref.DEFAULT_MODEL_KEY);
}
public static void setDefaultModel(String modelKey) {
Profile profileToUse = BraveLeoPrefUtils.getProfile();
if (profileToUse == null) {
Log.e(TAG, "BraveLeoPrefUtils.setDefaultModel profile is null");
return;
}
UserPrefs.get(profileToUse).setString(BravePref.DEFAULT_MODEL_KEY, modelKey);
}
}
@@ -11,6 +11,7 @@ import androidx.lifecycle.MutableLiveData;
import org.jni_zero.JNINamespace;
import org.jni_zero.NativeMethods;
import org.chromium.ai_chat.mojom.ModelWithSubtitle;
import org.chromium.base.Callback;
import org.chromium.base.Log;
import org.chromium.chrome.browser.app.BraveActivity;
@@ -56,6 +57,18 @@ public class BraveLeoUtils {
}
}
public static String getDefaultModelName(ModelWithSubtitle[] models) {
String defaultModelKey = BraveLeoPrefUtils.getDefaultModel();
for (ModelWithSubtitle model : models) {
if (model.model.key.equals(defaultModelKey)) {
return model.model.displayName;
}
}
return "";
}
@NativeMethods
public interface Natives {
void openLeoQuery(WebContents webContents, String query);
@@ -0,0 +1,46 @@
/* Copyright (c) 2024 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.settings;
import android.os.Bundle;
import androidx.annotation.Nullable;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.brave_leo.BraveLeoMojomHelper;
import org.chromium.chrome.browser.brave_leo.BraveLeoPrefUtils;
import org.chromium.components.browser_ui.settings.SettingsUtils;
public class BraveLeoDefaultModelPreferences extends BravePreferenceFragment
implements BraveLeoRadioButtonGroupDefaultModelPreference.RadioButtonsDelegate {
private static final String PREF_DEFAULT_MODEL_GROUP = "default_model";
private BraveLeoRadioButtonGroupDefaultModelPreference mRadioButtons;
@Override
public void onCreatePreferences(@Nullable Bundle savedInstanceState, String rootKey) {
SettingsUtils.addPreferencesFromResource(this, R.xml.brave_leo_default_model_preferences);
getActivity().setTitle(R.string.leo_default_model_pref_screen);
mRadioButtons =
(BraveLeoRadioButtonGroupDefaultModelPreference)
findPreference(PREF_DEFAULT_MODEL_GROUP);
mRadioButtons.initialize(this);
}
@Override
public void fetchModels() {
BraveLeoMojomHelper.getInstance(getProfile())
.getModels(
(models -> {
mRadioButtons.initializeModels(
models, BraveLeoPrefUtils.getDefaultModel());
}));
}
@Override
public void setDefaultModel(String key) {
BraveLeoPrefUtils.setDefaultModel(key);
}
}
@@ -1,43 +0,0 @@
/* 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.settings;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.preference.Preference;
import androidx.preference.PreferenceViewHolder;
import org.chromium.chrome.R;
import org.chromium.components.browser_ui.settings.ChromeBasePreference;
/**
* The preference used to reset Brave Leo.
*/
public class BraveLeoDescriptionPreference
extends ChromeBasePreference implements Preference.OnPreferenceClickListener {
/**
* Constructor for BraveLeoDescriptionPreference.
*/
public BraveLeoDescriptionPreference(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean onPreferenceClick(@NonNull Preference preference) {
return true;
}
@Override
public void onBindViewHolder(@NonNull PreferenceViewHolder holder) {
super.onBindViewHolder(holder);
TextView titleView = (TextView) holder.findViewById(android.R.id.summary);
assert titleView != null;
titleView.setTextAppearance(R.style.BraveLeoDescriptionText);
}
}
@@ -5,17 +5,21 @@
package org.chromium.chrome.browser.settings;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.preference.Preference;
import androidx.preference.PreferenceCategory;
import org.chromium.ai_chat.mojom.PremiumStatus;
import org.chromium.base.BravePreferenceKeys;
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.billing.InAppPurchaseWrapper;
import org.chromium.chrome.browser.brave_leo.BraveLeoMojomHelper;
import org.chromium.chrome.browser.brave_leo.BraveLeoPrefUtils;
import org.chromium.chrome.browser.brave_leo.BraveLeoUtils;
import org.chromium.chrome.browser.preferences.ChromeSharedPreferences;
@@ -28,14 +32,21 @@ public class BraveLeoPreferences extends BravePreferenceFragment
implements Preference.OnPreferenceChangeListener {
private static final String TAG = "BraveLeoPreferences";
private static final String PREF_LINK_SUBSCRIPTION = "link_subscription";
private static final String PREF_MANAGE_SUBSCRIPTION = "subscription_manage";
private static final String PREF_AUTOCOMPLETE = "autocomplete_switch";
private static final String PREF_SUBSCRIPTION_CATEGORY = "subscription_category";
private static final String PREF_DEFAULT_MODEL = "default_model";
private static final String LINK_SUBSCRIPTION_URL =
"https://account.brave.com?intent=connect-receipt&product=leo";
private PreferenceCategory mSubscriptionCategory;
@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
requireActivity().setTitle(R.string.menu_brave_leo);
SettingsUtils.addPreferencesFromResource(this, R.xml.brave_leo_preferences);
mSubscriptionCategory = findPreference(PREF_SUBSCRIPTION_CATEGORY);
assert mSubscriptionCategory != null;
BraveLeoUtils.verifySubscription(
(subscriptionActive) -> {
@@ -46,7 +57,7 @@ public class BraveLeoPreferences extends BravePreferenceFragment
@Override
public void onDestroyView() {
super.onDestroyView();
BraveLeoCMHelper.getInstance(getProfile()).destroy();
BraveLeoMojomHelper.getInstance(getProfile()).destroy();
}
@Override
@@ -65,22 +76,39 @@ public class BraveLeoPreferences extends BravePreferenceFragment
}
}
private void setModel() {
BraveLeoMojomHelper.getInstance(getProfile())
.getModels(
(models -> {
Preference pref = findPreference(PREF_DEFAULT_MODEL);
if (pref == null) {
Log.e(TAG, "Default model pref is null");
return;
}
pref.setSummary(BraveLeoUtils.getDefaultModelName(models));
}));
}
private void checkLinkPurchase() {
BraveLeoCMHelper.getInstance(getProfile())
BraveLeoMojomHelper.getInstance(getProfile())
.getPremiumStatus(
(status, info) -> {
if (status == PremiumStatus.ACTIVE
|| !BraveLeoPrefUtils.getIsSubscriptionActive(getProfile())) {
return;
}
ChromeBasePreference link_subscription =
ChromeBasePreference linkSubscription =
findPreference(PREF_LINK_SUBSCRIPTION);
if (link_subscription == null) {
ChromeBasePreference manageSubscription =
findPreference(PREF_MANAGE_SUBSCRIPTION);
if (linkSubscription == null
|| manageSubscription == null
|| mSubscriptionCategory == null) {
Log.e(TAG, "Subscription pref is null");
return;
}
link_subscription.setVisible(true);
link_subscription.setOnPreferenceClickListener(
mSubscriptionCategory.setVisible(true);
linkSubscription.setOnPreferenceClickListener(
preference -> {
try {
BraveActivity.getBraveActivity()
@@ -93,6 +121,17 @@ public class BraveLeoPreferences extends BravePreferenceFragment
}
return true;
});
manageSubscription.setOnPreferenceClickListener(
preference -> {
Intent browserIntent =
new Intent(
Intent.ACTION_VIEW,
Uri.parse(
InAppPurchaseWrapper
.MANAGE_SUBSCRIPTION_PAGE));
getActivity().startActivity(browserIntent);
return true;
});
});
}
@@ -106,4 +145,10 @@ public class BraveLeoPreferences extends BravePreferenceFragment
return true;
}
@Override
public void onResume() {
super.onResume();
setModel();
}
}
@@ -0,0 +1,92 @@
/* Copyright (c) 2024 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.settings;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.RadioGroup;
import androidx.preference.Preference;
import androidx.preference.PreferenceViewHolder;
import org.chromium.ai_chat.mojom.ModelWithSubtitle;
import org.chromium.chrome.R;
import org.chromium.components.browser_ui.widget.RadioButtonWithDescription;
import org.chromium.components.browser_ui.widget.RadioButtonWithDescriptionLayout;
import java.util.ArrayList;
import java.util.List;
public class BraveLeoRadioButtonGroupDefaultModelPreference extends Preference
implements RadioGroup.OnCheckedChangeListener {
/** This is a delegate that is implemented in BraveLeoDefaultModelPreferences */
public interface RadioButtonsDelegate {
default void fetchModels() {}
default void setDefaultModel(String key) {}
}
private RadioButtonWithDescriptionLayout mGroup;
private ModelWithSubtitle[] mModels;
private String mDefaultModelKey;
private Context mContext;
RadioButtonsDelegate mDelegate;
public BraveLeoRadioButtonGroupDefaultModelPreference(Context context, AttributeSet attrs) {
super(context, attrs);
mContext = context;
setLayoutResource(R.xml.brave_leo_radio_button_group_default_model_preference);
}
@Override
public void onBindViewHolder(PreferenceViewHolder holder) {
super.onBindViewHolder(holder);
mGroup = (RadioButtonWithDescriptionLayout) holder.findViewById(R.id.radio_button_layout);
assert mGroup != null;
mGroup.setOnCheckedChangeListener(this);
assert mDelegate != null;
mDelegate.fetchModels();
}
public void initialize(RadioButtonsDelegate delegate) {
mDelegate = delegate;
}
public void initializeModels(ModelWithSubtitle[] models, String defaultModel) {
mModels = models;
mDefaultModelKey = defaultModel;
if (mModels != null) {
List<RadioButtonWithDescription> buttons = new ArrayList<RadioButtonWithDescription>();
for (int i = 0; i < mModels.length; i++) {
buttons.add(
createRadioButtonWithDescription(
mModels[i].model.displayName,
mModels[i].subtitle,
mModels[i].model.key,
mModels[i].model.key.equals(mDefaultModelKey),
i));
}
mGroup.addButtons(buttons);
}
}
private RadioButtonWithDescription createRadioButtonWithDescription(
String primary, String description, Object tag, boolean checked, int id) {
RadioButtonWithDescription b = new RadioButtonWithDescription(mContext, null);
b.setPrimaryText(primary);
b.setDescriptionText(description);
b.setTag(tag);
b.setId(id);
b.setChecked(checked);
return b;
}
@Override
public void onCheckedChanged(RadioGroup radioGroup, int i) {
mDefaultModelKey = mModels[i].model.key;
mDelegate.setDefaultModel(mModels[i].model.key);
}
}
@@ -77,8 +77,6 @@ public class BraveVpnPreferences extends BravePreferenceFragment implements Brav
private static final String VPN_SUPPORT_PAGE =
"https://support.brave.com/hc/en-us/articles/4410838268429";
private static final String MANAGE_SUBSCRIPTION_PAGE =
"https://play.google.com/store/account/subscriptions";
private static final String DATE_FORMAT = "dd/MM/yyyy";
@@ -155,15 +153,20 @@ public class BraveVpnPreferences extends BravePreferenceFragment implements Brav
});
findPreference(PREF_SUBSCRIPTION_MANAGE)
.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference preference) {
Intent browserIntent =
new Intent(Intent.ACTION_VIEW, Uri.parse(MANAGE_SUBSCRIPTION_PAGE));
getActivity().startActivity(browserIntent);
return true;
}
});
.setOnPreferenceClickListener(
new Preference.OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference preference) {
Intent browserIntent =
new Intent(
Intent.ACTION_VIEW,
Uri.parse(
InAppPurchaseWrapper
.MANAGE_SUBSCRIPTION_PAGE));
getActivity().startActivity(browserIntent);
return true;
}
});
findPreference(PREF_SERVER_RESET_CONFIGURATION)
.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
-4
View File
@@ -309,10 +309,6 @@
<style name="BraveLeoResetTextColor" parent="Widget.AppCompat.TextView">
<item name="android:textColor">@color/leo_reset_text_color</item>
</style>
<style name="BraveLeoDescriptionText" parent="Widget.AppCompat.TextView">
<item name="android:textStyle">bold</item>
</style>
<style name="TimerBottomSheetDialogTheme"
parent="Theme.Design.Light.BottomSheetDialog">
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<!--* Copyright (c) 2024 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/. -->
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<org.chromium.chrome.browser.settings.BraveLeoRadioButtonGroupDefaultModelPreference
android:fragment="org.chromium.chrome.browser.settings.BraveLeoDefaultModelPreferences"
android:key="default_model" />
</PreferenceScreen>
+30 -16
View File
@@ -6,23 +6,37 @@
<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" />
<PreferenceCategory
android:key="leo_category"
android:title="@string/leo_summary">
<org.chromium.components.browser_ui.settings.ChromeSwitchPreference
android:key="autocomplete_switch"
android:title="@string/leo_autocomplete_pref"
android:defaultValue="true" />
<Preference
android:fragment="org.chromium.chrome.browser.settings.BraveLeoDefaultModelPreferences"
android:key="default_model"
android:title="@string/leo_default_model_pref" />
</PreferenceCategory>
<PreferenceCategory
android:key="subscription_category"
android:title="@string/leo_subscription_pref"
app:isPreferenceVisible="false">
<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"/>
<org.chromium.components.browser_ui.settings.ChromeBasePreference
android:key="subscription_manage"
android:title="@string/manage_subscription_leo"/>
</PreferenceCategory>
<org.chromium.components.browser_ui.settings.ChromeSwitchPreference
android:key="autocomplete_switch"
android:title="@string/leo_autocomplete_pref"
android:defaultValue="true" />
<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,20 @@
<?xml version="1.0" encoding="utf-8"?>
<!--* Copyright (c) 2024 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/. -->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:focusable="false">
<org.chromium.components.browser_ui.widget.RadioButtonWithDescriptionLayout
android:id="@+id/radio_button_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
@@ -1,68 +0,0 @@
/* 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,
mojom::PremiumInfoPtr premium_info) {
std::move(parent_callback).Run(premium_status, std::move(premium_info));
}
} // namespace ai_chat
@@ -0,0 +1,93 @@
/* 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_mojom_helper_android.h"
#include <utility>
#include <vector>
#include "brave/browser/skus/skus_service_factory.h"
#include "brave/build/android/jni_headers/BraveLeoMojomHelper_jni.h"
#include "brave/components/ai_chat/core/browser/models.h"
#include "chrome/browser/browser_process.h"
#include "components/grit/brave_components_strings.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"
#include "ui/base/l10n/l10n_util.h"
namespace ai_chat {
static jlong JNI_BraveLeoMojomHelper_Init(
JNIEnv* env,
const base::android::JavaParamRef<jobject>& jbrowser_context_handle) {
AIChatMojomHelperAndroid* cm_helper =
new AIChatMojomHelperAndroid(jbrowser_context_handle);
return reinterpret_cast<intptr_t>(cm_helper);
}
AIChatMojomHelperAndroid::AIChatMojomHelperAndroid(
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());
}
AIChatMojomHelperAndroid::~AIChatMojomHelperAndroid() = default;
void AIChatMojomHelperAndroid::Destroy(JNIEnv* env) {
delete this;
}
jlong AIChatMojomHelperAndroid::GetInterfaceToAndroidHelper(JNIEnv* env) {
mojo::PendingRemote<mojom::AIChatAndroidHelper> remote;
receivers_.Add(this, remote.InitWithNewPipeAndPassReceiver());
return static_cast<jlong>(remote.PassPipe().release().value());
}
void AIChatMojomHelperAndroid::GetPremiumStatus(
GetPremiumStatusCallback callback) {
credential_manager_->GetPremiumStatus(
base::BindOnce(&AIChatMojomHelperAndroid::OnPremiumStatusReceived,
weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
}
void AIChatMojomHelperAndroid::OnPremiumStatusReceived(
mojom::PageHandler::GetPremiumStatusCallback parent_callback,
mojom::PremiumStatus premium_status,
mojom::PremiumInfoPtr premium_info) {
std::move(parent_callback).Run(premium_status, std::move(premium_info));
}
void AIChatMojomHelperAndroid::GetModelsWithSubtitles(
GetModelsWithSubtitlesCallback callback) {
auto all_models = GetAllModels();
std::vector<mojom::ModelWithSubtitlePtr> models(all_models.size());
for (size_t i = 0; i < all_models.size(); i++) {
mojom::ModelWithSubtitle modelWithSubtitle;
modelWithSubtitle.model = all_models[i].Clone();
if (modelWithSubtitle.model->key == "chat-basic") {
modelWithSubtitle.subtitle =
l10n_util::GetStringUTF8(IDS_CHAT_UI_CHAT_BASIC_SUBTITLE);
} else if (modelWithSubtitle.model->key == "chat-leo-expanded") {
modelWithSubtitle.subtitle =
l10n_util::GetStringUTF8(IDS_CHAT_UI_CHAT_LEO_EXPANDED_SUBTITLE);
} else if (modelWithSubtitle.model->key == "chat-claude-instant") {
modelWithSubtitle.subtitle =
l10n_util::GetStringUTF8(IDS_CHAT_UI_CHAT_CLAUDE_INSTANT_SUBTITLE);
}
models[i] = modelWithSubtitle.Clone();
}
std::move(callback).Run(std::move(models));
}
} // namespace ai_chat
@@ -3,8 +3,8 @@
* 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_
#ifndef BRAVE_BROWSER_AI_CHAT_ANDROID_AI_CHAT_MOJOM_HELPER_ANDROID_H_
#define BRAVE_BROWSER_AI_CHAT_ANDROID_AI_CHAT_MOJOM_HELPER_ANDROID_H_
#include <memory>
@@ -17,16 +17,19 @@
namespace ai_chat {
class AIChatCMHelperAndroid : public mojom::CredentialManagerHelper {
class AIChatMojomHelperAndroid : public mojom::AIChatAndroidHelper {
public:
AIChatCMHelperAndroid(
AIChatMojomHelperAndroid(
const base::android::JavaParamRef<jobject>& jbrowser_context_handle);
~AIChatCMHelperAndroid() override;
~AIChatMojomHelperAndroid() override;
void Destroy(JNIEnv* env);
// mojom::AIChatAndroidHelper methods
void GetPremiumStatus(GetPremiumStatusCallback callback) override;
jlong GetInterfaceToCredentialManagerHelper(JNIEnv* env);
void GetModelsWithSubtitles(GetModelsWithSubtitlesCallback callback) override;
//
jlong GetInterfaceToAndroidHelper(JNIEnv* env);
private:
void OnPremiumStatusReceived(
@@ -34,10 +37,10 @@ class AIChatCMHelperAndroid : public mojom::CredentialManagerHelper {
mojom::PremiumStatus premium_status,
mojom::PremiumInfoPtr premium_info);
std::unique_ptr<AIChatCredentialManager> credential_manager_;
mojo::ReceiverSet<mojom::CredentialManagerHelper> receivers_;
base::WeakPtrFactory<AIChatCMHelperAndroid> weak_ptr_factory_{this};
mojo::ReceiverSet<mojom::AIChatAndroidHelper> receivers_;
base::WeakPtrFactory<AIChatMojomHelperAndroid> weak_ptr_factory_{this};
};
} // namespace ai_chat
#endif // BRAVE_BROWSER_AI_CHAT_ANDROID_AI_CHAT_CM_HELPER_ANDROID_H_
#endif // BRAVE_BROWSER_AI_CHAT_ANDROID_AI_CHAT_MOJOM_HELPER_ANDROID_H_
+2 -2
View File
@@ -4,8 +4,8 @@
# 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/ai_chat_mojom_helper_android.cc",
"//brave/browser/ai_chat/android/ai_chat_mojom_helper_android.h",
"//brave/browser/ai_chat/android/ai_chat_utils.cc",
]
@@ -4097,6 +4097,15 @@ If you don't accept this request, VPN will not reconnect and your internet conne
<message name="IDS_LEO_SUBSCRIPTION_UPGRADE_NOW" desc="Upgrade now button for Brave Leo subscription">
Upgrade now
</message>
<message name="IDS_LEO_SUBSCRIPTION_PREF" desc="Brave Leo Subscription section">
Subscription
</message>
<message name="IDS_LEO_DEFAULT_MODEL_PREF" desc="Title for Leo Default Model settings.">
Default model for new conversations
</message>
<message name="IDS_LEO_DEFAULT_MODEL_PREF_SCREEN" desc="Title for Leo Default Model settings screen.">
Default model
</message>
</messages>
</release>
</grit>
+1 -1
View File
@@ -212,7 +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/BraveLeoMojomHelper.java",
"//brave/android/java/org/chromium/chrome/browser/brave_leo/BraveLeoSettingsLauncherHelper.java",
"//brave/android/java/org/chromium/chrome/browser/brave_leo/BraveLeoUtils.java",
"//brave/android/java/org/chromium/chrome/browser/brave_news/BraveNewsControllerFactory.java",
+1 -1
View File
@@ -102,7 +102,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_leo/BraveLeoMojomHelper.java",
"//brave/android/java/org/chromium/chrome/browser/brave_leo/BraveLeoUtils.java",
"//brave/android/java/org/chromium/chrome/browser/brave_news/BraveNewsControllerFactory.java",
"//brave/android/java/org/chromium/chrome/browser/crypto_wallet/AssetRatioServiceFactory.java",
@@ -180,8 +180,15 @@ interface ChatUIPage {
};
[EnableIf=is_android]
interface CredentialManagerHelper {
struct ModelWithSubtitle {
Model model;
string subtitle;
};
[EnableIf=is_android]
interface AIChatAndroidHelper {
GetPremiumStatus() => (PremiumStatus status, PremiumInfo? info);
GetModelsWithSubtitles() => (array<ModelWithSubtitle> models);
};
[EnableIf=is_android]