Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 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/foreign_session_helper.h" | |
| 6 | |
| 7 #include <jni.h> | |
| 8 | |
| 9 #include "base/android/jni_string.h" | |
| 10 | |
| 11 #include "chrome/browser/chrome_notification_types.h" | |
| 12 #include "chrome/browser/prefs/scoped_user_pref_update.h" | |
| 13 #include "chrome/browser/profiles/profile_android.h" | |
| 14 #include "chrome/browser/sync/glue/session_model_associator.h" | |
| 15 #include "chrome/browser/sync/profile_sync_service.h" | |
| 16 #include "chrome/browser/sync/profile_sync_service_factory.h" | |
| 17 #include "chrome/browser/ui/android/tab_model/tab_model.h" | |
| 18 #include "chrome/browser/ui/android/tab_model/tab_model_list.h" | |
| 19 #include "chrome/common/pref_names.h" | |
| 20 #include "chrome/common/url_constants.h" | |
| 21 | |
| 22 #include "content/public/browser/notification_source.h" | |
| 23 #include "content/public/browser/user_metrics.h" | |
| 24 #include "content/public/browser/web_contents.h" | |
| 25 | |
| 26 #include "jni/ForeignSessionHelper_jni.h" | |
| 27 | |
| 28 using base::android::ScopedJavaGlobalRef; | |
| 29 using base::android::AttachCurrentThread; | |
| 30 using base::android::ConvertUTF16ToJavaString; | |
| 31 using base::android::ConvertUTF8ToJavaString; | |
| 32 using base::android::ConvertJavaStringToUTF8; | |
| 33 using browser_sync::SessionModelAssociator; | |
| 34 using browser_sync::SyncedSession; | |
| 35 | |
| 36 static jint Init(JNIEnv* env, jclass clazz, jobject profile) { | |
| 37 ForeignSessionHelper* foreign_session_helper = new ForeignSessionHelper( | |
| 38 ProfileAndroid::FromProfileAndroid(profile)); | |
| 39 return reinterpret_cast<jint>(foreign_session_helper); | |
| 40 } | |
| 41 | |
| 42 ForeignSessionHelper::ForeignSessionHelper(Profile* profile) { | |
| 43 profile_ = profile; | |
|
Ted C
2013/07/24 23:48:20
can you use an initializer list here instead?
Kibeom Kim (inactive)
2013/07/25 21:18:23
Done.
| |
| 44 callback_.Reset(); | |
|
Ted C
2013/07/24 23:48:20
is this necessary?
Kibeom Kim (inactive)
2013/07/25 21:18:23
No :( Done.
| |
| 45 | |
| 46 ProfileSyncService* service = ProfileSyncServiceFactory::GetInstance() | |
| 47 ->GetForProfile(profile); | |
|
Ted C
2013/07/24 23:48:20
having the -> on the previous line seems much more
Kibeom Kim (inactive)
2013/07/25 21:18:23
Done.
| |
| 48 | |
| 49 registrar_.Add(this, chrome::NOTIFICATION_SYNC_CONFIGURE_DONE, | |
| 50 content::Source<ProfileSyncService>(service)); | |
| 51 registrar_.Add(this, chrome::NOTIFICATION_FOREIGN_SESSION_UPDATED, | |
| 52 content::Source<Profile>(profile)); | |
| 53 registrar_.Add(this, chrome::NOTIFICATION_FOREIGN_SESSION_DISABLED, | |
| 54 content::Source<Profile>(profile)); | |
| 55 } | |
| 56 | |
| 57 void ForeignSessionHelper::Destroy(JNIEnv* env, jobject obj) { | |
| 58 delete this; | |
| 59 } | |
| 60 | |
| 61 jboolean ForeignSessionHelper::IsTabSyncEnabled(JNIEnv* env, jobject obj) { | |
| 62 ProfileSyncService* service = ProfileSyncServiceFactory::GetInstance() | |
| 63 ->GetForProfile(profile_); | |
|
Ted C
2013/07/24 23:48:20
same comment as above
Kibeom Kim (inactive)
2013/07/25 21:18:23
Done.
| |
| 64 return service && service->GetActiveDataTypes().Has(syncer::PROXY_TABS); | |
| 65 } | |
| 66 | |
| 67 void ForeignSessionHelper::SetOnForeignSessionCallback(JNIEnv* env, jobject obj, | |
|
Ted C
2013/07/24 23:48:20
I think if all the params don't fit on one line, t
Kibeom Kim (inactive)
2013/07/25 21:18:23
Done.
| |
| 68 jobject callback) { | |
| 69 callback_.Reset(env, callback); | |
| 70 } | |
| 71 | |
| 72 void ForeignSessionHelper::Observe( | |
| 73 int type, const content::NotificationSource& source, | |
| 74 const content::NotificationDetails& details) { | |
| 75 if (callback_.is_null()) | |
| 76 return; | |
| 77 | |
| 78 JNIEnv* env = AttachCurrentThread(); | |
| 79 | |
| 80 switch (type) { | |
| 81 case chrome::NOTIFICATION_FOREIGN_SESSION_DISABLED: | |
| 82 // Tab sync is disabled, so clean up data about collapsed sessions. | |
| 83 profile_->GetPrefs()->ClearPref( | |
| 84 prefs::kNtpCollapsedForeignSessions); | |
| 85 // Purposeful fall through. | |
| 86 case chrome::NOTIFICATION_SYNC_CONFIGURE_DONE: | |
| 87 case chrome::NOTIFICATION_FOREIGN_SESSION_UPDATED: | |
| 88 Java_OnForeignSessionCallback_onUpdated(env, callback_.obj()); | |
| 89 break; | |
| 90 default: | |
| 91 NOTREACHED(); | |
| 92 } | |
| 93 } | |
| 94 | |
| 95 jboolean ForeignSessionHelper::GetForeignSessions(JNIEnv* env, jobject obj, | |
| 96 jobject result) { | |
| 97 SessionModelAssociator* associator = GetSessionModelAssociator(); | |
| 98 if (associator == NULL) | |
|
Ted C
2013/07/24 23:48:20
if (!associator)
Kibeom Kim (inactive)
2013/07/25 21:18:23
Done.
| |
| 99 return false; | |
| 100 | |
| 101 std::vector<const browser_sync::SyncedSession*> sessions; | |
| 102 if (!associator->GetAllForeignSessions(&sessions)) | |
| 103 return false; | |
| 104 | |
| 105 // Use a pref to keep track of sessions that were collapsed by the user. | |
| 106 // To prevent the pref from accumulating stale sessions, clear it each time | |
| 107 // and only add back sessions that are still current. | |
| 108 DictionaryPrefUpdate pref_update(profile_->GetPrefs(), | |
| 109 prefs::kNtpCollapsedForeignSessions); | |
| 110 DictionaryValue* current_collapsed_sessions = pref_update.Get(); | |
| 111 scoped_ptr<DictionaryValue> collapsed_sessions( | |
| 112 current_collapsed_sessions->DeepCopy()); | |
| 113 current_collapsed_sessions->Clear(); | |
| 114 | |
| 115 // Note: we don't own the SyncedSessions themselves. | |
| 116 for (size_t i = 0; i < sessions.size(); ++i) { | |
| 117 const browser_sync::SyncedSession* session = sessions[i]; | |
| 118 | |
| 119 const bool is_collapsed = collapsed_sessions->HasKey(session->session_tag); | |
| 120 | |
| 121 if (is_collapsed) | |
| 122 current_collapsed_sessions->SetBoolean(session->session_tag, true); | |
| 123 | |
| 124 Java_ForeignSessionHelper_pushSession( | |
| 125 env, result, | |
| 126 ConvertUTF8ToJavaString(env, session->session_tag).Release(), | |
| 127 ConvertUTF8ToJavaString(env, session->session_name).Release(), | |
| 128 ConvertUTF8ToJavaString(env, session->DeviceTypeAsString()).Release(), | |
| 129 session->modified_time.ToInternalValue()); | |
| 130 | |
| 131 for (SyncedSession::SyncedWindowMap::const_iterator it = | |
| 132 session->windows.begin(); it != session->windows.end(); ++it) { | |
| 133 SessionWindow* window = it->second; | |
| 134 | |
| 135 if (window->tabs.empty()) { | |
| 136 NOTREACHED(); | |
| 137 continue; | |
| 138 } | |
| 139 | |
| 140 Java_ForeignSessionHelper_pushWindow( | |
| 141 env, result, | |
| 142 window->timestamp.ToInternalValue(), | |
| 143 window->window_id.id()); | |
| 144 | |
| 145 for (std::vector<SessionTab*>::iterator iit = window->tabs.begin(); | |
|
Ted C
2013/07/24 23:48:20
Might consider having helper methods for the inner
Kibeom Kim (inactive)
2013/07/25 21:18:23
Done.
| |
| 146 iit != window->tabs.end(); ++iit) { | |
| 147 const SessionTab &tab = **iit; | |
| 148 | |
| 149 if (tab.navigations.empty()) | |
| 150 continue; | |
| 151 | |
| 152 int selected_index = std::min( | |
| 153 tab.current_navigation_index, | |
| 154 static_cast<int>(tab.navigations.size() - 1)); | |
| 155 const ::sessions::SerializedNavigationEntry& current_navigation = | |
| 156 tab.navigations.at(selected_index); | |
| 157 | |
| 158 GURL tab_url = current_navigation.virtual_url(); | |
| 159 if (tab_url == GURL(chrome::kChromeUINewTabURL)) | |
| 160 continue; | |
| 161 | |
| 162 Java_ForeignSessionHelper_pushTab( | |
| 163 env, result, | |
| 164 ConvertUTF8ToJavaString(env, tab_url.spec()).Release(), | |
| 165 ConvertUTF16ToJavaString(env, current_navigation.title()).Release(), | |
| 166 tab.timestamp.ToInternalValue(), | |
| 167 tab.tab_id.id()); | |
| 168 } | |
| 169 } | |
| 170 } | |
| 171 | |
| 172 return true; | |
| 173 } | |
| 174 | |
| 175 jboolean ForeignSessionHelper::OpenForeignSessionTab(JNIEnv* env, jobject obj, | |
| 176 jstring session_tag, | |
| 177 jint tab_id) { | |
| 178 content::RecordComputedAction("MobileNTPForeignSession"); | |
| 179 | |
| 180 SessionModelAssociator* associator = GetSessionModelAssociator(); | |
| 181 if (!associator) { | |
| 182 LOG(ERROR) << "Null SessionModelAssociator returned."; | |
| 183 return false; | |
| 184 } | |
| 185 | |
| 186 const SessionTab* tab; | |
| 187 | |
| 188 if (!associator->GetForeignTab(ConvertJavaStringToUTF8(env, session_tag), | |
| 189 tab_id, &tab)) { | |
| 190 LOG(ERROR) << "Failed to load foreign tab."; | |
| 191 return false; | |
| 192 } | |
| 193 | |
| 194 if (tab->navigations.empty()) { | |
| 195 LOG(ERROR) << "Foreign tab no longer has valid navigations."; | |
| 196 return false; | |
| 197 } | |
| 198 | |
| 199 TabModel* tab_model = TabModelList::GetTabModelWithProfile(profile_); | |
| 200 DCHECK(tab_model); | |
| 201 if (!tab_model) | |
| 202 return false; | |
| 203 | |
| 204 std::vector<content::NavigationEntry*> entries = | |
| 205 sessions::SerializedNavigationEntry::ToNavigationEntries( | |
| 206 tab->navigations, profile_); | |
| 207 content::WebContents* new_web_contents = content::WebContents::Create( | |
| 208 content::WebContents::CreateParams(profile_)); | |
| 209 int selected_index = tab->normalized_navigation_index(); | |
| 210 new_web_contents->GetController().Restore( | |
| 211 selected_index, | |
| 212 content::NavigationController::RESTORE_LAST_SESSION_EXITED_CLEANLY, | |
| 213 &entries); | |
| 214 tab_model->CreateTab(new_web_contents); | |
| 215 | |
| 216 return true; | |
| 217 } | |
| 218 | |
| 219 void ForeignSessionHelper::SetForeignSessionCollapsed(JNIEnv* env, jobject obj, | |
| 220 jstring session_tag, | |
| 221 jboolean is_collapsed) { | |
| 222 // Store session tags for collapsed sessions in a preference so that the | |
| 223 // collapsed state persists. | |
| 224 PrefService* prefs = profile_->GetPrefs(); | |
| 225 DictionaryPrefUpdate update(prefs, prefs::kNtpCollapsedForeignSessions); | |
| 226 if (is_collapsed) | |
| 227 update.Get()->SetBoolean(ConvertJavaStringToUTF8(env, session_tag), true); | |
| 228 else | |
| 229 update.Get()->Remove(ConvertJavaStringToUTF8(env, session_tag), NULL); | |
| 230 } | |
| 231 | |
| 232 void ForeignSessionHelper::DeleteForeignSession(JNIEnv* env, jobject obj, | |
| 233 jstring session_tag) { | |
| 234 SessionModelAssociator* associator = GetSessionModelAssociator(); | |
| 235 if (associator) | |
| 236 associator->DeleteForeignSession(ConvertJavaStringToUTF8(env, session_tag)); | |
| 237 } | |
| 238 | |
| 239 SessionModelAssociator* ForeignSessionHelper::GetSessionModelAssociator() { | |
| 240 ProfileSyncService* service = ProfileSyncServiceFactory::GetInstance() | |
| 241 ->GetForProfile(profile_); | |
| 242 | |
| 243 // Only return the associator if it exists and it is done syncing sessions. | |
| 244 if (!service || !service->ShouldPushChanges()) | |
| 245 return NULL; | |
| 246 | |
| 247 return service->GetSessionModelAssociator(); | |
| 248 } | |
| 249 | |
| 250 // static | |
| 251 bool ForeignSessionHelper::RegisterForeignSessionHelper(JNIEnv* env) { | |
| 252 return RegisterNativesImpl(env); | |
| 253 } | |
| OLD | NEW |