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 | |
newt (away)
2013/07/27 00:24:51
don't need newlines between includes, except a sin
Kibeom Kim (inactive)
2013/07/27 23:02:38
Done.
| |
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::ScopedJavaLocalRef; | |
30 using base::android::AttachCurrentThread; | |
31 using base::android::ConvertUTF16ToJavaString; | |
32 using base::android::ConvertUTF8ToJavaString; | |
33 using base::android::ConvertJavaStringToUTF8; | |
34 using browser_sync::SessionModelAssociator; | |
35 using browser_sync::SyncedSession; | |
36 | |
37 namespace { | |
38 | |
39 SessionModelAssociator* GetSessionModelAssociator(Profile* profile) { | |
40 ProfileSyncService* service = ProfileSyncServiceFactory::GetInstance()-> | |
41 GetForProfile(profile); | |
42 | |
43 // Only return the associator if it exists and it is done syncing sessions. | |
44 if (!service || !service->ShouldPushChanges()) | |
45 return NULL; | |
46 | |
47 return service->GetSessionModelAssociator(); | |
48 } | |
49 | |
50 void CopyTabsToJava( | |
51 JNIEnv* env, | |
52 const SessionWindow* window, | |
53 ScopedJavaLocalRef<jobject>& j_window) { | |
54 for (std::vector<SessionTab*>::const_iterator iit = window->tabs.begin(); | |
newt (away)
2013/07/27 00:24:51
"iit" -> "it"?
Kibeom Kim (inactive)
2013/07/27 23:02:38
iit was a mistake :( I chose tab_it. But let me kn
| |
55 iit != window->tabs.end(); ++iit) { | |
56 const SessionTab &tab = **iit; | |
57 | |
58 if (tab.navigations.empty()) | |
59 continue; | |
60 | |
61 int selected_index = std::min(tab.current_navigation_index, | |
newt (away)
2013/07/27 00:24:51
seems odd to check this against the upper boundary
Kibeom Kim (inactive)
2013/07/27 23:02:38
Done.
| |
62 static_cast<int>(tab.navigations.size() - 1)); | |
63 const ::sessions::SerializedNavigationEntry& current_navigation = | |
64 tab.navigations.at(selected_index); | |
65 | |
66 GURL tab_url = current_navigation.virtual_url(); | |
67 if (tab_url == GURL(chrome::kChromeUINewTabURL)) | |
68 continue; | |
69 | |
70 Java_ForeignSessionHelper_pushTab( | |
71 env, j_window.obj(), | |
72 ConvertUTF8ToJavaString(env, tab_url.spec()).Release(), | |
73 ConvertUTF16ToJavaString(env, current_navigation.title()).Release(), | |
74 tab.timestamp.ToInternalValue(), tab.tab_id.id()); | |
75 } | |
76 } | |
77 | |
78 void CopyWindowsToJava( | |
79 JNIEnv* env, | |
80 const SyncedSession* session, | |
81 ScopedJavaLocalRef<jobject>& j_session) { | |
82 for (SyncedSession::SyncedWindowMap::const_iterator it = | |
83 session->windows.begin(); it != session->windows.end(); ++it) { | |
84 const SessionWindow* window = it->second; | |
85 | |
86 if (window->tabs.empty()) { | |
newt (away)
2013/07/27 00:24:51
this check seems superfluous. the code will work j
Kibeom Kim (inactive)
2013/07/27 23:02:38
Done.
| |
87 NOTREACHED(); | |
88 continue; | |
89 } | |
90 | |
91 ScopedJavaLocalRef<jobject> last_pushed_window; | |
92 last_pushed_window.Reset( | |
93 Java_ForeignSessionHelper_pushWindow( | |
94 env, j_session.obj(), window->timestamp.ToInternalValue(), | |
95 window->window_id.id())); | |
96 | |
97 CopyTabsToJava(env, window, last_pushed_window); | |
98 } | |
99 } | |
100 | |
101 } // namespace | |
102 | |
103 static jint Init(JNIEnv* env, jclass clazz, jobject profile) { | |
104 ForeignSessionHelper* foreign_session_helper = new ForeignSessionHelper( | |
105 ProfileAndroid::FromProfileAndroid(profile)); | |
106 return reinterpret_cast<jint>(foreign_session_helper); | |
107 } | |
108 | |
109 ForeignSessionHelper::ForeignSessionHelper(Profile* profile) | |
110 : profile_(profile) { | |
111 ProfileSyncService* service =ProfileSyncServiceFactory::GetInstance()-> | |
newt (away)
2013/07/27 00:24:51
space after "="
Kibeom Kim (inactive)
2013/07/27 23:02:38
Done.
| |
112 GetForProfile(profile); | |
113 | |
114 registrar_.Add(this, chrome::NOTIFICATION_SYNC_CONFIGURE_DONE, | |
115 content::Source<ProfileSyncService>(service)); | |
116 registrar_.Add(this, chrome::NOTIFICATION_FOREIGN_SESSION_UPDATED, | |
117 content::Source<Profile>(profile)); | |
118 registrar_.Add(this, chrome::NOTIFICATION_FOREIGN_SESSION_DISABLED, | |
119 content::Source<Profile>(profile)); | |
120 } | |
121 | |
122 void ForeignSessionHelper::Destroy(JNIEnv* env, jobject obj) { | |
123 delete this; | |
124 } | |
125 | |
126 jboolean ForeignSessionHelper::IsTabSyncEnabled(JNIEnv* env, jobject obj) { | |
127 ProfileSyncService* service = ProfileSyncServiceFactory::GetInstance()-> | |
128 GetForProfile(profile_); | |
129 return service && service->GetActiveDataTypes().Has(syncer::PROXY_TABS); | |
130 } | |
131 | |
132 void ForeignSessionHelper::SetOnForeignSessionCallback(JNIEnv* env, | |
133 jobject obj, | |
134 jobject callback) { | |
135 callback_.Reset(env, callback); | |
136 } | |
137 | |
138 void ForeignSessionHelper::Observe( | |
139 int type, const content::NotificationSource& source, | |
140 const content::NotificationDetails& details) { | |
141 if (callback_.is_null()) | |
142 return; | |
143 | |
144 JNIEnv* env = AttachCurrentThread(); | |
145 | |
146 switch (type) { | |
147 case chrome::NOTIFICATION_FOREIGN_SESSION_DISABLED: | |
148 // Tab sync is disabled, so clean up data about collapsed sessions. | |
149 profile_->GetPrefs()->ClearPref( | |
150 prefs::kNtpCollapsedForeignSessions); | |
151 // Purposeful fall through. | |
152 case chrome::NOTIFICATION_SYNC_CONFIGURE_DONE: | |
153 case chrome::NOTIFICATION_FOREIGN_SESSION_UPDATED: | |
154 Java_OnForeignSessionCallback_onUpdated(env, callback_.obj()); | |
155 break; | |
156 default: | |
157 NOTREACHED(); | |
158 } | |
159 } | |
160 | |
161 jboolean ForeignSessionHelper::GetForeignSessions(JNIEnv* env, | |
162 jobject obj, | |
163 jobject result) { | |
164 SessionModelAssociator* associator = GetSessionModelAssociator(profile_); | |
165 if (!associator) | |
166 return false; | |
167 | |
168 std::vector<const browser_sync::SyncedSession*> sessions; | |
169 if (!associator->GetAllForeignSessions(&sessions)) | |
170 return false; | |
171 | |
172 // Use a pref to keep track of sessions that were collapsed by the user. | |
173 // To prevent the pref from accumulating stale sessions, clear it each time | |
174 // and only add back sessions that are still current. | |
175 DictionaryPrefUpdate pref_update(profile_->GetPrefs(), | |
176 prefs::kNtpCollapsedForeignSessions); | |
177 DictionaryValue* current_collapsed_sessions = pref_update.Get(); | |
newt (away)
2013/07/27 00:24:51
wouldn't "old_collapsed_sessions" make sense?
Kibeom Kim (inactive)
2013/07/27 23:02:38
Hmm. I chose pref_collapsed_sessions. Done.
| |
178 scoped_ptr<DictionaryValue> collapsed_sessions( | |
179 current_collapsed_sessions->DeepCopy()); | |
180 current_collapsed_sessions->Clear(); | |
181 | |
182 ScopedJavaLocalRef<jobject> last_pushed_session; | |
183 ScopedJavaLocalRef<jobject> last_pushed_window; | |
184 | |
185 // Note: we don't own the SyncedSessions themselves. | |
186 for (size_t i = 0; i < sessions.size(); ++i) { | |
187 const browser_sync::SyncedSession* session = sessions[i]; | |
188 | |
189 const bool is_collapsed = collapsed_sessions->HasKey(session->session_tag); | |
190 | |
191 if (is_collapsed) | |
192 current_collapsed_sessions->SetBoolean(session->session_tag, true); | |
193 | |
194 last_pushed_session.Reset( | |
195 Java_ForeignSessionHelper_pushSession( | |
196 env, | |
197 result, | |
198 ConvertUTF8ToJavaString(env, session->session_tag).Release(), | |
199 ConvertUTF8ToJavaString(env, session->session_name).Release(), | |
200 ConvertUTF8ToJavaString(env, | |
201 session->DeviceTypeAsString()).Release(), | |
202 session->modified_time.ToInternalValue())); | |
203 | |
204 CopyWindowsToJava(env, session, last_pushed_session); | |
205 } | |
206 | |
207 return true; | |
208 } | |
209 | |
210 jboolean ForeignSessionHelper::OpenForeignSessionTab(JNIEnv* env, | |
211 jobject obj, | |
212 jstring session_tag, | |
213 jint tab_id) { | |
214 content::RecordComputedAction("MobileNTPForeignSession"); | |
newt (away)
2013/07/27 00:24:51
this action is actually obsolete. I'd leave this o
Kibeom Kim (inactive)
2013/07/27 23:02:38
Done.
| |
215 | |
216 SessionModelAssociator* associator = GetSessionModelAssociator(profile_); | |
217 if (!associator) { | |
218 LOG(ERROR) << "Null SessionModelAssociator returned."; | |
219 return false; | |
220 } | |
221 | |
222 const SessionTab* tab; | |
223 | |
224 if (!associator->GetForeignTab(ConvertJavaStringToUTF8(env, session_tag), | |
225 tab_id, &tab)) { | |
226 LOG(ERROR) << "Failed to load foreign tab."; | |
227 return false; | |
228 } | |
229 | |
230 if (tab->navigations.empty()) { | |
231 LOG(ERROR) << "Foreign tab no longer has valid navigations."; | |
232 return false; | |
233 } | |
234 | |
235 TabModel* tab_model = TabModelList::GetTabModelWithProfile(profile_); | |
236 DCHECK(tab_model); | |
237 if (!tab_model) | |
238 return false; | |
239 | |
240 std::vector<content::NavigationEntry*> entries = | |
241 sessions::SerializedNavigationEntry::ToNavigationEntries( | |
242 tab->navigations, profile_); | |
243 content::WebContents* new_web_contents = content::WebContents::Create( | |
244 content::WebContents::CreateParams(profile_)); | |
245 int selected_index = tab->normalized_navigation_index(); | |
246 new_web_contents->GetController().Restore( | |
247 selected_index, | |
248 content::NavigationController::RESTORE_LAST_SESSION_EXITED_CLEANLY, | |
249 &entries); | |
250 tab_model->CreateTab(new_web_contents); | |
251 | |
252 return true; | |
253 } | |
254 | |
255 void ForeignSessionHelper::SetForeignSessionCollapsed(JNIEnv* env, jobject obj, | |
256 jstring session_tag, | |
257 jboolean is_collapsed) { | |
258 // Store session tags for collapsed sessions in a preference so that the | |
259 // collapsed state persists. | |
260 PrefService* prefs = profile_->GetPrefs(); | |
261 DictionaryPrefUpdate update(prefs, prefs::kNtpCollapsedForeignSessions); | |
262 if (is_collapsed) | |
263 update.Get()->SetBoolean(ConvertJavaStringToUTF8(env, session_tag), true); | |
264 else | |
265 update.Get()->Remove(ConvertJavaStringToUTF8(env, session_tag), NULL); | |
266 } | |
267 | |
268 void ForeignSessionHelper::DeleteForeignSession(JNIEnv* env, jobject obj, | |
269 jstring session_tag) { | |
270 SessionModelAssociator* associator = GetSessionModelAssociator(profile_); | |
271 if (associator) | |
272 associator->DeleteForeignSession(ConvertJavaStringToUTF8(env, session_tag)); | |
273 } | |
274 | |
275 ForeignSessionHelper::~ForeignSessionHelper() { | |
Ted C
2013/07/26 23:48:32
one of the instances where the ordering shouldn't
Kibeom Kim (inactive)
2013/07/27 00:03:26
Done.
| |
276 } | |
277 | |
278 // static | |
279 bool ForeignSessionHelper::RegisterForeignSessionHelper(JNIEnv* env) { | |
280 return RegisterNativesImpl(env); | |
281 } | |
OLD | NEW |