blob: ed9b3e5f644a093ae65cba40d3a079c144c4710f [file] [log] [blame]
Scott Violet009c09c2020-01-18 00:57:181// Copyright 2020 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "weblayer/browser/browser_impl.h"
6
7#include <algorithm>
8
Scott Violet87450ce2020-01-23 01:56:259#include "base/path_service.h"
10#include "components/base32/base32.h"
11#include "content/public/browser/browser_context.h"
Scott Violet009c09c2020-01-18 00:57:1812#include "weblayer/browser/profile_impl.h"
Scott Violet87450ce2020-01-23 01:56:2513#include "weblayer/browser/session_service.h"
Scott Violet009c09c2020-01-18 00:57:1814#include "weblayer/browser/tab_impl.h"
Scott Violet87450ce2020-01-23 01:56:2515#include "weblayer/common/weblayer_paths.h"
Scott Violet009c09c2020-01-18 00:57:1816#include "weblayer/public/browser_observer.h"
17
18#if defined(OS_ANDROID)
19#include "base/android/callback_android.h"
Scott Violetbf8b8aa72020-01-28 19:37:3220#include "base/android/jni_array.h"
Scott Violet009c09c2020-01-18 00:57:1821#include "base/android/jni_string.h"
22#include "base/json/json_writer.h"
23#include "weblayer/browser/java/jni/BrowserImpl_jni.h"
24#endif
25
26namespace weblayer {
27
Scott Violetbf8b8aa72020-01-28 19:37:3228std::unique_ptr<Browser> Browser::Create(
29 Profile* profile,
30 const PersistenceInfo* persistence_info) {
Scott Violet87450ce2020-01-23 01:56:2531 return std::make_unique<BrowserImpl>(static_cast<ProfileImpl*>(profile),
Scott Violetbf8b8aa72020-01-28 19:37:3232 persistence_info);
Scott Violet009c09c2020-01-18 00:57:1833}
34
35#if defined(OS_ANDROID)
36BrowserImpl::BrowserImpl(ProfileImpl* profile,
Scott Violetbf8b8aa72020-01-28 19:37:3237 const PersistenceInfo* persistence_info,
Scott Violet009c09c2020-01-18 00:57:1838 const base::android::JavaParamRef<jobject>& java_impl)
Scott Violetbf8b8aa72020-01-28 19:37:3239 : BrowserImpl(profile, persistence_info) {
Scott Violet009c09c2020-01-18 00:57:1840 java_impl_ = java_impl;
41}
42#endif
43
Scott Violet87450ce2020-01-23 01:56:2544BrowserImpl::BrowserImpl(ProfileImpl* profile,
Scott Violetbf8b8aa72020-01-28 19:37:3245 const PersistenceInfo* persistence_info)
46 : profile_(profile),
47 persistence_id_(persistence_info ? persistence_info->id : std::string()) {
48 if (persistence_info)
49 CreateSessionServiceAndRestore(*persistence_info);
Scott Violet87450ce2020-01-23 01:56:2550}
Scott Violet009c09c2020-01-18 00:57:1851
52BrowserImpl::~BrowserImpl() {
53 while (!tabs_.empty()) {
54 Tab* last_tab = tabs_.back();
55 RemoveTab(last_tab);
56 DCHECK(!base::Contains(tabs_, last_tab));
57 }
58}
59
Scott Violet58ad5a32020-01-23 22:07:2760TabImpl* BrowserImpl::CreateTabForSessionRestore(
61 std::unique_ptr<content::WebContents> web_contents) {
62 TabImpl* tab = new TabImpl(profile_, std::move(web_contents));
63#if defined(OS_ANDROID)
64 // The Java side takes ownership of Tab.
65 Java_BrowserImpl_createTabForSessionRestore(
66 base::android::AttachCurrentThread(), java_impl_,
67 reinterpret_cast<jlong>(tab));
68#endif
69 AddTab(tab);
70 return tab;
71}
72
Scott Violet009c09c2020-01-18 00:57:1873#if defined(OS_ANDROID)
74void BrowserImpl::AddTab(JNIEnv* env,
75 const base::android::JavaParamRef<jobject>& caller,
76 long native_tab) {
77 AddTab(reinterpret_cast<TabImpl*>(native_tab));
78}
79
80void BrowserImpl::RemoveTab(JNIEnv* env,
81 const base::android::JavaParamRef<jobject>& caller,
82 long native_tab) {
83 RemoveTab(reinterpret_cast<TabImpl*>(native_tab));
84}
85
86base::android::ScopedJavaLocalRef<jobjectArray> BrowserImpl::GetTabs(
87 JNIEnv* env,
88 const base::android::JavaParamRef<jobject>& caller) {
89 base::android::ScopedJavaLocalRef<jclass> clazz =
90 base::android::GetClass(env, "org/chromium/weblayer_private/TabImpl");
91 jobjectArray tabs = env->NewObjectArray(tabs_.size(), clazz.obj(),
92 nullptr /* initialElement */);
93 base::android::CheckException(env);
94
95 for (size_t i = 0; i < tabs_.size(); ++i) {
96 TabImpl* tab = static_cast<TabImpl*>(tabs_[i]);
97 env->SetObjectArrayElement(tabs, i, tab->GetJavaTab().obj());
98 }
99 return base::android::ScopedJavaLocalRef<jobjectArray>(env, tabs);
100}
101
102void BrowserImpl::SetActiveTab(
103 JNIEnv* env,
104 const base::android::JavaParamRef<jobject>& caller,
105 long native_tab) {
106 SetActiveTab(reinterpret_cast<TabImpl*>(native_tab));
107}
108
109base::android::ScopedJavaLocalRef<jobject> BrowserImpl::GetActiveTab(
110 JNIEnv* env,
111 const base::android::JavaParamRef<jobject>& caller) {
112 if (!active_tab_)
113 return nullptr;
114 return base::android::ScopedJavaLocalRef<jobject>(active_tab_->GetJavaTab());
115}
Scott Violet58ad5a32020-01-23 22:07:27116
117void BrowserImpl::PrepareForShutdown(
118 JNIEnv* env,
119 const base::android::JavaParamRef<jobject>& caller) {
120 PrepareForShutdown();
121}
122
123base::android::ScopedJavaLocalRef<jstring> BrowserImpl::GetPersistenceId(
124 JNIEnv* env,
125 const base::android::JavaParamRef<jobject>& caller) {
126 return base::android::ScopedJavaLocalRef<jstring>(
Scott Violetbf8b8aa72020-01-28 19:37:32127 base::android::ConvertUTF8ToJavaString(env, GetPersistenceId()));
128}
129
130void BrowserImpl::SaveSessionServiceIfNecessary(
131 JNIEnv* env,
132 const base::android::JavaParamRef<jobject>& caller) {
133 session_service_->SaveIfNecessary();
134}
135
136base::android::ScopedJavaLocalRef<jbyteArray>
137BrowserImpl::GetSessionServiceCryptoKey(
138 JNIEnv* env,
139 const base::android::JavaParamRef<jobject>& caller) {
140 std::vector<uint8_t> key;
141 if (session_service_)
142 key = session_service_->GetCryptoKey();
143 return base::android::ToJavaByteArray(env, key);
Scott Violet58ad5a32020-01-23 22:07:27144}
145
Scott Violet009c09c2020-01-18 00:57:18146#endif
147
148void BrowserImpl::AddTab(Tab* tab) {
149 DCHECK(tab);
150 TabImpl* tab_impl = static_cast<TabImpl*>(tab);
151 if (tab_impl->browser() != this && tab_impl->browser())
152 tab_impl->browser()->RemoveTab(tab);
153 tabs_.push_back(tab);
154 tab_impl->set_browser(this);
155#if defined(OS_ANDROID)
156 Java_BrowserImpl_onTabAdded(base::android::AttachCurrentThread(), java_impl_,
157 tab ? tab_impl->GetJavaTab() : nullptr);
158#endif
159 for (BrowserObserver& obs : browser_observers_)
160 obs.OnTabAdded(tab);
161}
162
163void BrowserImpl::RemoveTab(Tab* tab) {
164 TabImpl* tab_impl = static_cast<TabImpl*>(tab);
165 DCHECK_EQ(this, tab_impl->browser());
166 static_cast<TabImpl*>(tab)->set_browser(nullptr);
167 tabs_.erase(std::find(tabs_.begin(), tabs_.end(), tab));
168 const bool active_tab_changed = active_tab_ == tab;
169 if (active_tab_changed)
170 active_tab_ = nullptr;
171#if defined(OS_ANDROID)
172 if (active_tab_changed) {
173 Java_BrowserImpl_onActiveTabChanged(
174 base::android::AttachCurrentThread(), java_impl_,
175 active_tab_ ? static_cast<TabImpl*>(active_tab_)->GetJavaTab()
176 : nullptr);
177 }
178 Java_BrowserImpl_onTabRemoved(base::android::AttachCurrentThread(),
179 java_impl_,
180 tab ? tab_impl->GetJavaTab() : nullptr);
181#endif
182 if (active_tab_changed) {
183 for (BrowserObserver& obs : browser_observers_)
184 obs.OnActiveTabChanged(active_tab_);
185 }
186 for (BrowserObserver& obs : browser_observers_)
187 obs.OnTabRemoved(tab, active_tab_changed);
188}
189
190void BrowserImpl::SetActiveTab(Tab* tab) {
191 if (GetActiveTab() == tab)
192 return;
193 // TODO: currently the java side sets visibility, this code likely should
194 // too and it should be removed from the java side.
195 active_tab_ = static_cast<TabImpl*>(tab);
196#if defined(OS_ANDROID)
197 Java_BrowserImpl_onActiveTabChanged(
198 base::android::AttachCurrentThread(), java_impl_,
199 active_tab_ ? active_tab_->GetJavaTab() : nullptr);
200#endif
201 for (BrowserObserver& obs : browser_observers_)
202 obs.OnActiveTabChanged(active_tab_);
203 if (active_tab_)
204 active_tab_->web_contents()->GetController().LoadIfNecessary();
205}
206
207Tab* BrowserImpl::GetActiveTab() {
208 return active_tab_;
209}
210
211const std::vector<Tab*>& BrowserImpl::GetTabs() {
212 return tabs_;
213}
214
Scott Violet87450ce2020-01-23 01:56:25215void BrowserImpl::PrepareForShutdown() {
216 session_service_.reset();
217}
218
Scott Violetbf8b8aa72020-01-28 19:37:32219std::string BrowserImpl::GetPersistenceId() {
Scott Violet58ad5a32020-01-23 22:07:27220 return persistence_id_;
221}
222
Scott Violet009c09c2020-01-18 00:57:18223void BrowserImpl::AddObserver(BrowserObserver* observer) {
224 browser_observers_.AddObserver(observer);
225}
226
227void BrowserImpl::RemoveObserver(BrowserObserver* observer) {
228 browser_observers_.RemoveObserver(observer);
229}
230
Scott Violet87450ce2020-01-23 01:56:25231base::FilePath BrowserImpl::GetSessionServiceDataPath() {
232 base::FilePath base_path;
233 if (profile_->GetBrowserContext()->IsOffTheRecord()) {
234 CHECK(base::PathService::Get(DIR_USER_DATA, &base_path));
235 base_path = base_path.AppendASCII("Incognito Restore Data");
236 } else {
237 base_path = profile_->data_path().AppendASCII("Restore Data");
238 }
Scott Violetbf8b8aa72020-01-28 19:37:32239 DCHECK(!GetPersistenceId().empty());
240 const std::string encoded_name = base32::Base32Encode(GetPersistenceId());
Scott Violet87450ce2020-01-23 01:56:25241 return base_path.AppendASCII("State" + encoded_name);
242}
243
Scott Violetbf8b8aa72020-01-28 19:37:32244void BrowserImpl::CreateSessionServiceAndRestore(
245 const PersistenceInfo& persistence_info) {
246 session_service_ = std::make_unique<SessionService>(
247 GetSessionServiceDataPath(), this, persistence_info.last_crypto_key);
Scott Violet87450ce2020-01-23 01:56:25248}
249
Scott Violet009c09c2020-01-18 00:57:18250#if defined(OS_ANDROID)
251static jlong JNI_BrowserImpl_CreateBrowser(
252 JNIEnv* env,
253 jlong profile,
Scott Violetbf8b8aa72020-01-28 19:37:32254 const base::android::JavaParamRef<jstring>& j_persistence_id,
255 const base::android::JavaParamRef<jbyteArray>& j_persistence_crypto_key,
Scott Violet009c09c2020-01-18 00:57:18256 const base::android::JavaParamRef<jobject>& java_impl) {
Scott Violetbf8b8aa72020-01-28 19:37:32257 Browser::PersistenceInfo persistence_info;
258 Browser::PersistenceInfo* persistence_info_ptr = nullptr;
259
260 if (j_persistence_id.obj()) {
261 const std::string persistence_id =
262 base::android::ConvertJavaStringToUTF8(j_persistence_id);
263 if (!persistence_id.empty()) {
264 persistence_info.id = persistence_id;
265 if (j_persistence_crypto_key.obj()) {
266 base::android::JavaByteArrayToByteVector(
267 env, j_persistence_crypto_key, &(persistence_info.last_crypto_key));
268 }
269 persistence_info_ptr = &persistence_info;
270 }
271 }
272 return reinterpret_cast<intptr_t>(
273 new BrowserImpl(reinterpret_cast<ProfileImpl*>(profile),
274 persistence_info_ptr, java_impl));
Scott Violet009c09c2020-01-18 00:57:18275}
276
277static void JNI_BrowserImpl_DeleteBrowser(JNIEnv* env, jlong browser) {
278 delete reinterpret_cast<BrowserImpl*>(browser);
279}
280#endif
281
282} // namespace weblayer