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 jint j_disposition) { 94 if (!tab_restore_service_) 95 return false; 96 97 // Find and remove the corresponding tab entry from TabRestoreService. 98 // We take ownership of the returned tab. 99 scoped_ptr<TabRestoreService::Tab> tab_entry( 100 tab_restore_service_->RemoveTabEntryById(recent_tab_id)); 101 if (!tab_entry) 102 return false; 103 104 TabAndroid* tab_android = TabAndroid::GetNativeTab(env, jtab); 105 if (!tab_android) 106 return false; 107 content::WebContents* web_contents = tab_android->web_contents(); 108 if (!web_contents) 109 return false; 110 111 // RestoreForeignSessionTab needs a SessionTab. 112 SessionTab session_tab; 113 session_tab.current_navigation_index = tab_entry->current_navigation_index; 114 session_tab.navigations = tab_entry->navigations; 115 116 WindowOpenDisposition disposition = 117 static_cast<WindowOpenDisposition>(j_disposition); 118 SessionRestore::RestoreForeignSessionTab(web_contents, 119 session_tab, 120 disposition); 121 return true; 122 } 123 124 void RecentlyClosedTabsBridge::ClearRecentlyClosedTabs(JNIEnv* env, 125 jobject obj) { 126 EnsureTabRestoreService(); 127 if (tab_restore_service_) 128 tab_restore_service_->ClearEntries(); 129 } 130 131 void RecentlyClosedTabsBridge::TabRestoreServiceChanged( 132 TabRestoreService* service) { 133 if (callback_.is_null()) 134 return; 135 JNIEnv* env = AttachCurrentThread(); 136 Java_RecentlyClosedCallback_onUpdated(env, callback_.obj()); 137 } 138 139 void RecentlyClosedTabsBridge::TabRestoreServiceDestroyed( 140 TabRestoreService* service) { 141 tab_restore_service_ = NULL; 142 } 143 144 void RecentlyClosedTabsBridge::EnsureTabRestoreService() { 145 if (tab_restore_service_) 146 return; 147 148 tab_restore_service_ = TabRestoreServiceFactory::GetForProfile(profile_); 149 150 // TabRestoreServiceFactory::GetForProfile() can return NULL (e.g. in 151 // incognito mode). 152 if (tab_restore_service_) { 153 // This does nothing if the tabs have already been loaded or they 154 // shouldn't be loaded. 155 tab_restore_service_->LoadTabsFromLastSession(); 156 tab_restore_service_->AddObserver(this); 157 } 158 } 159 160 static jlong Init(JNIEnv* env, jobject obj, jobject jprofile) { 161 RecentlyClosedTabsBridge* bridge = new RecentlyClosedTabsBridge( 162 ProfileAndroid::FromProfileAndroid(jprofile)); 163 return reinterpret_cast<intptr_t>(bridge); 164 } 165 166 // static 167 bool RecentlyClosedTabsBridge::Register(JNIEnv* env) { 168 return RegisterNativesImpl(env); 169 } 170