Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[AI Chat]: Android history setting #26988

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions android/brave_java_resources.gni
Original file line number Diff line number Diff line change
Expand Up @@ -794,6 +794,7 @@ brave_java_resources = [
"java/res/layout/brave_custom_tabs_toolbar.xml",
"java/res/layout/brave_dialog_preference.xml",
"java/res/layout/brave_exit_confirmation.xml",
"java/res/layout/brave_leo_clear_history_dialog.xml",
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bridiver would it be okay if we landed this brave_java_resources addition? I'm not an Android expert, so it'll take me a while to work out the proper way of doing this and I'm going on PTO on Monday

"java/res/layout/brave_leo_reset_dialog.xml",
"java/res/layout/brave_news_card_menu.xml",
"java/res/layout/brave_news_load_new_content.xml",
Expand Down
1 change: 1 addition & 0 deletions android/java/org/chromium/base/BraveFeatureList.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ public abstract class BraveFeatureList {
public static final String BRAVE_FORGET_FIRST_PARTY_STORAGE = "BraveForgetFirstPartyStorage";
public static final String BRAVE_REQUEST_OTR_TAB = "BraveRequestOTRTab";
public static final String AI_CHAT = "AIChat";
public static final String AI_CHAT_HISTORY = "AIChatHistory";
public static final String BRAVE_SHOW_STRICT_FINGERPRINTING_MODE =
"BraveShowStrictFingerprintingMode";
public static final String BRAVE_DAY_ZERO_EXPERIMENT = "BraveDayZeroExperiment";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,24 @@ public static void setChatPurchaseToken(String token) {
}
}

public static boolean getIsHistoryEnabled() {
Profile profileToUse = BraveLeoPrefUtils.getProfile();
if (profileToUse == null) {
Log.e(TAG, "BraveLeoPrefUtils.getIsHistoryEnabled profile is null");
return false;
}
return UserPrefs.get(profileToUse).getBoolean(BravePref.BRAVE_CHAT_STORAGE_ENABLED);
}

public static void setIsHistoryEnabled(boolean isEnabled) {
Profile profileToUse = BraveLeoPrefUtils.getProfile();
if (profileToUse == null) {
Log.e(TAG, "BraveLeoPrefUtils.getIsHistoryEnabled profile is null");
return;
}
UserPrefs.get(profileToUse).setBoolean(BravePref.BRAVE_CHAT_STORAGE_ENABLED, isEnabled);
}

private static void createFetchOrder(Profile profileToUse) {
BraveLeoMojomHelper.getInstance(profileToUse)
.createOrderId(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,20 @@

package org.chromium.chrome.browser.settings;

import android.content.Context;
import android.content.DialogInterface;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.preference.Preference;
import androidx.preference.PreferenceCategory;

import org.chromium.ai_chat.mojom.ModelWithSubtitle;
import org.chromium.ai_chat.mojom.PremiumStatus;
import org.chromium.base.BraveFeatureList;
import org.chromium.base.BravePreferenceKeys;
import org.chromium.base.Log;
import org.chromium.base.supplier.ObservableSupplier;
Expand All @@ -23,6 +29,7 @@
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.flags.ChromeFeatureList;
import org.chromium.chrome.browser.preferences.ChromeSharedPreferences;
import org.chromium.chrome.browser.util.TabUtils;
import org.chromium.components.browser_ui.settings.ChromeBasePreference;
Expand All @@ -36,10 +43,12 @@ public class BraveLeoPreferences extends BravePreferenceFragment
private static final String PREF_MANAGE_SUBSCRIPTION = "subscription_manage";
private static final String PREF_GO_PREMIUM = "go_premium";
private static final String PREF_AUTOCOMPLETE = "autocomplete_switch";
private static final String PREF_HISTORY = "history_switch";
private static final String PREF_SUBSCRIPTION_CATEGORY = "subscription_category";
private static final String PREF_DEFAULT_MODEL = "default_model";

private final ObservableSupplierImpl<String> mPageTitle = new ObservableSupplierImpl<>();
private ChromeSwitchPreference mHistory;

@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
Expand All @@ -66,6 +75,14 @@ public void onCreate(Bundle savedInstanceState) {
BravePreferenceKeys.BRAVE_LEO_AUTOCOMPLETE, true));
}
}

if (history instanceof ChromeSwitchPreference) {
mHistory = (ChromeSwitchPreference) history;
mHistory.setOnPreferenceChangeListener(this);
mHistory.setChecked(BraveLeoPrefUtils.getIsHistoryEnabled());
mHistory.setVisible(ChromeFeatureList.isEnabled(BraveFeatureList.AI_CHAT_HISTORY));
}

BraveLeoUtils.verifySubscription(
(subscriptionActive) -> {
checkLinkPurchase();
Expand Down Expand Up @@ -145,12 +162,48 @@ private void checkLinkPurchase() {
});
}

private void showConfirmClearHistoryDialog() {
LayoutInflater inflater =
(LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View view = inflater.inflate(R.layout.brave_leo_clear_history_dialog, null);

DialogInterface.OnClickListener onClickListener =
(dialog, button) -> {
if (button == AlertDialog.BUTTON_POSITIVE) {
BraveLeoPrefUtils.setIsHistoryEnabled(false);
mHistory.setChecked(false);
} else {
dialog.dismiss();
}
};

AlertDialog.Builder alert =
new AlertDialog.Builder(getContext(), R.style.ThemeOverlay_BrowserUI_AlertDialog);
AlertDialog alertDialog =
alert.setTitle(R.string.leo_clear_history_title)
.setView(view)
.setPositiveButton(R.string.brave_leo_confirm_text, onClickListener)
.setNegativeButton(R.string.cancel, onClickListener)
.create();
alertDialog.getDelegate().setHandleNativeActionModesEnabled(false);
alertDialog.show();
}

@Override
public boolean onPreferenceChange(@NonNull Preference preference, Object o) {
String key = preference.getKey();
boolean enabled = (boolean) o;
if (PREF_AUTOCOMPLETE.equals(key)) {
ChromeSharedPreferences.getInstance()
.writeBoolean(BravePreferenceKeys.BRAVE_LEO_AUTOCOMPLETE, (boolean) o);
.writeBoolean(BravePreferenceKeys.BRAVE_LEO_AUTOCOMPLETE, enabled);
}
if (PREF_HISTORY.equals(key)) {
if (enabled) {
BraveLeoPrefUtils.setIsHistoryEnabled(enabled);
} else {
showConfirmClearHistoryDialog();
return false;
}
}

return true;
Expand Down
11 changes: 11 additions & 0 deletions android/java/res/layout/brave_leo_clear_history_dialog.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?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/. -->

<TextView 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:text="@string/brave_leo_clear_history_confirmation" />
6 changes: 6 additions & 0 deletions android/java/res/xml/brave_leo_preferences.xml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@
android:title="@string/leo_autocomplete_pref"
android:defaultValue="true" />

<org.chromium.components.browser_ui.settings.ChromeSwitchPreference
android:key="history_switch"
android:title="@string/leo_history_pref"
android:defaultValue="true"
app:isPreferenceVisible="false" />

<Preference
android:fragment="org.chromium.chrome.browser.settings.BraveLeoDefaultModelPreferences"
android:key="default_model"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,7 @@ const PrefsUtil::TypedPrefMap& BravePrefsUtil::GetAllowlistedKeys() {
settings_api::PrefType::kBoolean;

// Leo Assistant pref
(*s_brave_allowlist)[ai_chat::prefs::kStorageEnabled] =
(*s_brave_allowlist)[ai_chat::prefs::kBraveChatStorageEnabled] =
settings_api::PrefType::kBoolean;
(*s_brave_allowlist)[ai_chat::prefs::kBraveChatAutocompleteProviderEnabled] =
settings_api::PrefType::kBoolean;
Expand Down
9 changes: 9 additions & 0 deletions browser/ui/android/strings/android_brave_strings.grd
Original file line number Diff line number Diff line change
Expand Up @@ -3688,6 +3688,9 @@ If you don't accept this request, VPN will not reconnect and your internet conne
<message name="IDS_LEO_SUMMARY" desc="Title for Leo options.">
Leo is an AI-powered smart assistant, built right into the browser
</message>
<message name="IDS_LEO_HISTORY_PREF" desc="Title for Leo history preference.">
Store conversation history
</message>
<message name="IDS_LEO_AUTOCOMPLETE_PREF" desc="Title for Leo Autocomplete suggestions.">
Show autocomplete suggestions in address bar
</message>
Expand All @@ -3697,6 +3700,12 @@ If you don't accept this request, VPN will not reconnect and your internet conne
<message name="IDS_BRAVE_LEO_RESET_CONFIRMATION" desc="Title for preference to reset Leo.">
Resetting the Leo assistant will require you to opt-in to use Leo in the future and will also clear your chat history. Clearing your chat history will delete all your previous conversations with Leo. This action cannot be undone.
</message>
<message name="IDS_LEO_CLEAR_HISTORY_TITLE" desc="Title for confirmation dialog to clear Leo history.">
Clear chat history
</message>
<message name="IDS_BRAVE_LEO_CLEAR_HISTORY_CONFIRMATION" desc="Confirmation text for clearing Leo history.">
Disabling chat history will delete all your previous conversations with Leo. This action cannot be undone.
</message>
<message name="IDS_BRAVE_LEO_CONFIRM_TEXT" desc="Text for Leo confirm button text.">
Confirm
</message>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,12 @@
#include "net/base/features.h"
#include "third_party/blink/public/common/features.h"

#define BRAVE_AI_CHAT_FLAG &ai_chat::features::kAIChat,
#define BRAVE_AI_CHAT_FLAGS \
&ai_chat::features::kAIChat, &ai_chat::features::kAIChatHistory,

// clang-format off
#define kForceWebContentsDarkMode kForceWebContentsDarkMode, \
BRAVE_AI_CHAT_FLAG \
BRAVE_AI_CHAT_FLAGS \
&brave_rewards::features::kBraveRewards, \
&brave_search_conversion::features::kOmniboxBanner, \
&brave_vpn::features::kBraveVPNLinkSubscriptionAndroidUI, \
Expand All @@ -51,7 +52,7 @@

#include "src/chrome/browser/flags/android/chrome_feature_list.cc"
#undef kForceWebContentsDarkMode
#undef BRAVE_AI_CHAT_FLAG
#undef BRAVE_AI_CHAT_FLAGS

namespace chrome {
namespace android {
Expand Down
11 changes: 6 additions & 5 deletions components/ai_chat/core/browser/ai_chat_service.cc
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ AIChatService::AIChatService(
base::BindRepeating(&AIChatService::OnUserOptedIn,
weak_ptr_factory_.GetWeakPtr()));
pref_change_registrar_.Add(
prefs::kStorageEnabled,
prefs::kBraveChatStorageEnabled,
base::BindRepeating(&AIChatService::MaybeInitStorage,
weak_ptr_factory_.GetWeakPtr()));
pref_change_registrar_.Add(
Expand Down Expand Up @@ -377,7 +377,7 @@ void AIChatService::OnOsCryptAsyncReady(os_crypt_async::Encryptor encryptor,
return;
}
// Pref might have changed since we started this process
if (!profile_prefs_->GetBoolean(prefs::kStorageEnabled)) {
if (!profile_prefs_->GetBoolean(prefs::kBraveChatStorageEnabled)) {
return;
}
ai_chat_db_ = base::SequenceBound<AIChatDatabase>(
Expand Down Expand Up @@ -554,7 +554,7 @@ void AIChatService::MarkAgreementAccepted() {
}

void AIChatService::EnableStoragePref() {
profile_prefs_->SetBoolean(prefs::kStorageEnabled, true);
profile_prefs_->SetBoolean(prefs::kBraveChatStorageEnabled, true);
}

void AIChatService::DismissStorageNotice() {
Expand Down Expand Up @@ -688,7 +688,8 @@ mojom::ServiceStatePtr AIChatService::BuildState() {
!last_accepted_disclaimer.is_null() &&
last_accepted_disclaimer < base::Time::Now() - base::Days(1);

bool is_storage_enabled = profile_prefs_->GetBoolean(prefs::kStorageEnabled);
bool is_storage_enabled =
profile_prefs_->GetBoolean(prefs::kBraveChatStorageEnabled);

mojom::ServiceStatePtr state = mojom::ServiceState::New();
state->has_accepted_agreement = is_user_opted_in;
Expand All @@ -707,7 +708,7 @@ void AIChatService::OnStateChanged() {

bool AIChatService::IsAIChatHistoryEnabled() {
return (features::IsAIChatHistoryEnabled() &&
profile_prefs_->GetBoolean(prefs::kStorageEnabled));
profile_prefs_->GetBoolean(prefs::kBraveChatStorageEnabled));
}

void AIChatService::OnRequestInProgressChanged(ConversationHandler* handler,
Expand Down
4 changes: 2 additions & 2 deletions components/ai_chat/core/browser/ai_chat_service_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -631,7 +631,7 @@ TEST_P(AIChatServiceUnitTest, MaybeInitStorage_DisableStoragePref) {
ExpectVisibleConversationsSize(FROM_HERE, 3);

// Disable storage
prefs_.SetBoolean(prefs::kStorageEnabled, false);
prefs_.SetBoolean(prefs::kBraveChatStorageEnabled, false);
// Wait for OnConversationListChanged which indicates data has been removed
task_environment_.RunUntilIdle();

Expand All @@ -648,7 +648,7 @@ TEST_P(AIChatServiceUnitTest, MaybeInitStorage_DisableStoragePref) {
ExpectVisibleConversationsSize(FROM_HERE, 0);

// Re-enable storage preference
prefs_.SetBoolean(prefs::kStorageEnabled, true);
prefs_.SetBoolean(prefs::kBraveChatStorageEnabled, true);
// Conversations are no longer in persistant storage
ExpectVisibleConversationsSize(FROM_HERE, 0);
}
Expand Down
2 changes: 1 addition & 1 deletion components/ai_chat/core/common/pref_names.cc
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ namespace ai_chat::prefs {
void RegisterProfilePrefs(PrefRegistrySimple* registry) {
if (ai_chat::features::IsAIChatEnabled()) {
registry->RegisterTimePref(kLastAcceptedDisclaimer, {});
registry->RegisterBooleanPref(kStorageEnabled, true);
registry->RegisterBooleanPref(kBraveChatStorageEnabled, true);
registry->RegisterBooleanPref(kBraveChatAutocompleteProviderEnabled, true);
registry->RegisterBooleanPref(kUserDismissedPremiumPrompt, false);
registry->RegisterBooleanPref(kUserDismissedStorageNotice, false);
Expand Down
3 changes: 2 additions & 1 deletion components/ai_chat/core/common/pref_names.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ namespace ai_chat::prefs {

inline constexpr char kLastAcceptedDisclaimer[] =
"brave.ai_chat.last_accepted_disclaimer";
inline constexpr char kStorageEnabled[] = "brave.ai_chat.storage_enabled";
inline constexpr char kBraveChatStorageEnabled[] =
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we're already in the ai_chat namespace so do we need to add the prefix again? IF we do, perhaps kBraveChat -> kBraveAIChat...

Copy link
Contributor Author

@fallaciousreasoning fallaciousreasoning Dec 11, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I added it because this isn't in the namespace in android so without this its BravePrefs.STORAGE_ENABLED

I went with kBraveChat because that's what everything else is using

"brave.ai_chat.storage_enabled";
inline constexpr char kBraveChatAutocompleteProviderEnabled[] =
"brave.ai_chat.autocomplete_provider_enabled";
inline constexpr char kBraveChatP3AChatCountWeeklyStorage[] =
Expand Down
Loading