blob: 611d40379e18f5fc11330e30b81a383a3234f571 [file] [log] [blame]
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/android/recently_closed_tabs_bridge.h"
#include "base/android/jni_string.h"
#include "chrome/browser/android/tab_android.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_android.h"
#include "chrome/browser/sessions/session_restore.h"
#include "chrome/browser/sessions/tab_restore_service_factory.h"
#include "chrome/browser/ui/android/tab_model/tab_model_list.h"
#include "components/sessions/core/live_tab.h"
#include "components/sessions/core/tab_restore_service.h"
#include "content/public/browser/web_contents.h"
#include "jni/RecentlyClosedBridge_jni.h"
using base::android::AttachCurrentThread;
using base::android::ConvertUTF16ToJavaString;
using base::android::ConvertUTF8ToJavaString;
using base::android::JavaParamRef;
using base::android::JavaRef;
using base::android::ScopedJavaGlobalRef;
namespace {
void JNI_RecentlyClosedBridge_AddTabToList(
JNIEnv* env,
const sessions::TabRestoreService::Tab& tab,
const JavaRef<jobject>& jtabs_list) {
const sessions::SerializedNavigationEntry& current_navigation =
tab.navigations.at(tab.current_navigation_index);
Java_RecentlyClosedBridge_pushTab(
env, jtabs_list, tab.id.id(),
ConvertUTF16ToJavaString(env, current_navigation.title()),
ConvertUTF8ToJavaString(env, current_navigation.virtual_url().spec()));
}
void JNI_RecentlyClosedBridge_AddTabsToList(
JNIEnv* env,
const sessions::TabRestoreService::Entries& entries,
const JavaRef<jobject>& jtabs_list,
int max_tab_count) {
int added_count = 0;
for (const auto& entry : entries) {
DCHECK_EQ(entry->type, sessions::TabRestoreService::TAB);
if (entry->type == sessions::TabRestoreService::TAB) {
auto& tab = static_cast<const sessions::TabRestoreService::Tab&>(*entry);
JNI_RecentlyClosedBridge_AddTabToList(env, tab, jtabs_list);
if (++added_count == max_tab_count)
break;
}
}
}
} // namespace
RecentlyClosedTabsBridge::RecentlyClosedTabsBridge(
ScopedJavaGlobalRef<jobject> jbridge,
Profile* profile)
: bridge_(std::move(jbridge)),
profile_(profile),
tab_restore_service_(nullptr) {}
RecentlyClosedTabsBridge::~RecentlyClosedTabsBridge() {
if (tab_restore_service_)
tab_restore_service_->RemoveObserver(this);
}
void RecentlyClosedTabsBridge::Destroy(JNIEnv* env,
const JavaParamRef<jobject>& obj) {
delete this;
}
jboolean RecentlyClosedTabsBridge::GetRecentlyClosedTabs(
JNIEnv* env,
const JavaParamRef<jobject>& obj,
const JavaParamRef<jobject>& jtabs_list,
jint max_tab_count) {
EnsureTabRestoreService();
if (!tab_restore_service_)
return false;
JNI_RecentlyClosedBridge_AddTabsToList(env, tab_restore_service_->entries(),
jtabs_list, max_tab_count);
return true;
}
jboolean RecentlyClosedTabsBridge::OpenRecentlyClosedTab(
JNIEnv* env,
const JavaParamRef<jobject>& obj,
const JavaParamRef<jobject>& jtab,
jint recent_tab_id,
jint j_disposition) {
if (!tab_restore_service_)
return false;
// Find and remove the corresponding tab entry from TabRestoreService.
// We take ownership of the returned tab.
std::unique_ptr<sessions::TabRestoreService::Tab> tab_entry(
tab_restore_service_->RemoveTabEntryById(
SessionID::FromSerializedValue(recent_tab_id)));
if (!tab_entry)
return false;
TabAndroid* tab_android = TabAndroid::GetNativeTab(env, jtab);
if (!tab_android)
return false;
content::WebContents* web_contents = tab_android->web_contents();
if (!web_contents)
return false;
// RestoreForeignSessionTab needs a SessionTab.
sessions::SessionTab session_tab;
session_tab.current_navigation_index = tab_entry->current_navigation_index;
session_tab.navigations = tab_entry->navigations;
WindowOpenDisposition disposition =
static_cast<WindowOpenDisposition>(j_disposition);
SessionRestore::RestoreForeignSessionTab(web_contents,
session_tab,
disposition);
return true;
}
jboolean RecentlyClosedTabsBridge::OpenMostRecentlyClosedTab(
JNIEnv* env,
const base::android::JavaParamRef<jobject>& obj) {
EnsureTabRestoreService();
if (!tab_restore_service_ || TabModelList::empty() ||
tab_restore_service_->entries().empty())
return false;
// Passing nullptr here because LiveTabContext will be determined later by
// a call to AndroidLiveTabContext::FindLiveTabContextWithID in
// ChromeTabRestoreServiceClient.
std::vector<sessions::LiveTab*> restored_tab =
tab_restore_service_->RestoreMostRecentEntry(nullptr);
return !restored_tab.empty();
}
void RecentlyClosedTabsBridge::ClearRecentlyClosedTabs(
JNIEnv* env,
const JavaParamRef<jobject>& obj) {
EnsureTabRestoreService();
if (tab_restore_service_)
tab_restore_service_->ClearEntries();
}
void RecentlyClosedTabsBridge::TabRestoreServiceChanged(
sessions::TabRestoreService* service) {
Java_RecentlyClosedBridge_onUpdated(AttachCurrentThread(), bridge_);
}
void RecentlyClosedTabsBridge::TabRestoreServiceDestroyed(
sessions::TabRestoreService* service) {
tab_restore_service_ = NULL;
}
void RecentlyClosedTabsBridge::EnsureTabRestoreService() {
if (tab_restore_service_)
return;
tab_restore_service_ = TabRestoreServiceFactory::GetForProfile(profile_);
// TabRestoreServiceFactory::GetForProfile() can return NULL (e.g. in
// incognito mode).
if (tab_restore_service_) {
// This does nothing if the tabs have already been loaded or they
// shouldn't be loaded.
tab_restore_service_->LoadTabsFromLastSession();
tab_restore_service_->AddObserver(this);
}
}
static jlong JNI_RecentlyClosedBridge_Init(
JNIEnv* env,
const JavaParamRef<jobject>& jbridge,
const JavaParamRef<jobject>& jprofile) {
RecentlyClosedTabsBridge* bridge = new RecentlyClosedTabsBridge(
ScopedJavaGlobalRef<jobject>(env, jbridge.obj()),
ProfileAndroid::FromProfileAndroid(jprofile));
return reinterpret_cast<intptr_t>(bridge);
}