1 // Copyright 2013 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 "chrome/browser/android/recently_closed_tabs_bridge.h" 6 7 #include "base/android/jni_string.h" 8 #include "chrome/browser/android/tab_android.h" 9 #include "chrome/browser/profiles/profile.h" 10 #include "chrome/browser/profiles/profile_android.h" 11 #include "chrome/browser/sessions/session_restore.h" 12 #include "chrome/browser/sessions/tab_restore_service.h" 13 #include "chrome/browser/sessions/tab_restore_service_factory.h" 14 #include "content/public/browser/web_contents.h" 15 #include "jni/RecentlyClosedBridge_jni.h" 16 17 using base::android::AttachCurrentThread; 18 using base::android::ConvertUTF16ToJavaString; 19 using base::android::ConvertUTF8ToJavaString; 20 using base::android::ScopedJavaLocalRef; 21 22 namespace { 23 24 void AddTabToList(JNIEnv* env, 25 TabRestoreService::Entry* entry, 26 jobject jtabs_list) { 27 const TabRestoreService::Tab* tab = 28 static_cast<TabRestoreService::Tab*>(entry); 29 const sessions::SerializedNavigationEntry& current_navigation = 30 tab->navigations.at(tab->current_navigation_index); 31 Java_RecentlyClosedBridge_pushTab( 32 env, jtabs_list, entry->id, 33 ConvertUTF16ToJavaString(env, current_navigation.title()).Release(), 34 ConvertUTF8ToJavaString(env, current_navigation.virtual_url().spec()) 35 .Release()); 36 } 37 38 void AddTabsToList(JNIEnv* env, 39 const TabRestoreService::Entries& entries, 40 jobject jtabs_list, 41 int max_tab_count) { 42 int added_count = 0; 43 for (TabRestoreService::Entries::const_iterator it = entries.begin(); 44 it != entries.end() && added_count < max_tab_count; ++it) { 45 TabRestoreService::Entry* entry = *it; 46 DCHECK_EQ(entry->type, TabRestoreService::TAB); 47 if (entry->type == TabRestoreService::TAB) { 48 AddTabToList(env, entry, jtabs_list); 49 ++added_count; 50 } 51 } 52 } 53 54 } // namespace 55 56 RecentlyClosedTabsBridge::RecentlyClosedTabsBridge(Profile* profile) 57 : profile_(profile), 58 tab_restore_service_(NULL) { 59 } 60 61 RecentlyClosedTabsBridge::~RecentlyClosedTabsBridge() { 62 if (tab_restore_service_) 63 tab_restore_service_->RemoveObserver(this); 64 } 65 66 void RecentlyClosedTabsBridge::Destroy(JNIEnv* env, jobject obj) { 67 delete this; 68 } 69 70 void RecentlyClosedTabsBridge::SetRecentlyClosedCallback(JNIEnv* env, 71 jobject obj, 72 jobject jcallback) { 73 callback_.Reset(env, jcallback); 74 } 75 76 jboolean RecentlyClosedTabsBridge::GetRecentlyClosedTabs(JNIEnv* env, 77 jobject obj, 78 jobject jtabs_list, 79 jint max_tab_count) { 80 EnsureTabRestoreService(); 81 if (!tab_restore_service_) 82 return false; 83 84 AddTabsToList(env, tab_restore_service_->entries(), jtabs_list, 85 max_tab_count); 86 return true; 87 } 88 89 jboolean RecentlyClosedTabsBridge::OpenRecentlyClosedTab(JNIEnv* env, 90 jobject obj, 91 jobject jtab, 92 jint recent_tab_id) { 93 if (!tab_restore_service_) 94 return false; 95 96 // Find and remove the corresponding tab entry from TabRestoreService. 97 // We take ownership of the returned tab. 98 scoped_ptr<TabRestoreService::Tab> tab_entry( 99 tab_restore_service_->RemoveTabEntryById(recent_tab_id)); 100 if (!tab_entry) 101 return false; 102 103 TabAndroid* tab_android = TabAndroid::GetNativeTab(env, jtab); 104 if (!tab_android) 105 return false; 106 content::WebContents* web_contents = tab_android->web_contents(); 107 if (!web_contents) 108 return false; 109 110 // RestoreForeignSessionTab needs a SessionTab. 111 SessionTab session_tab; 112 session_tab.current_navigation_index = tab_entry->current_navigation_index; 113 session_tab.navigations = tab_entry->navigations; 114 115 SessionRestore::RestoreForeignSessionTab(web_contents, 116 session_tab, 117 CURRENT_TAB); 118 return true; 119 } 120 121 void RecentlyClosedTabsBridge::ClearRecentlyClosedTabs(JNIEnv* env, 122 jobject obj) { 123 EnsureTabRestoreService(); 124 if (tab_restore_service_) 125 tab_restore_service_->ClearEntries(); 126 } 127 128 void RecentlyClosedTabsBridge::TabRestoreServiceChanged( 129 TabRestoreService* service) { 130 if (callback_.is_null()) 131 return; 132 JNIEnv* env = AttachCurrentThread(); 133 Java_RecentlyClosedCallback_onUpdated(env, callback_.obj()); 134 } 135 136 void RecentlyClosedTabsBridge::TabRestoreServiceDestroyed( 137 TabRestoreService* service) { 138 tab_restore_service_ = NULL; 139 } 140 141 void RecentlyClosedTabsBridge::EnsureTabRestoreService() { 142 if (tab_restore_service_) 143 return; 144 145 tab_restore_service_ = TabRestoreServiceFactory::GetForProfile(profile_); 146 147 // TabRestoreServiceFactory::GetForProfile() can return NULL (e.g. in 148 // incognito mode). 149 if (tab_restore_service_) { 150 // This does nothing if the tabs have already been loaded or they 151 // shouldn't be loaded. 152 tab_restore_service_->LoadTabsFromLastSession(); 153 tab_restore_service_->AddObserver(this); 154 } 155 } 156 157 static jlong Init(JNIEnv* env, jobject obj, jobject jprofile) { 158 RecentlyClosedTabsBridge* bridge = new RecentlyClosedTabsBridge( 159 ProfileAndroid::FromProfileAndroid(jprofile)); 160 return reinterpret_cast<intptr_t>(bridge); 161 } 162 163 // static 164 bool RecentlyClosedTabsBridge::Register(JNIEnv* env) { 165 return RegisterNativesImpl(env); 166 } 167