Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(113)

Side by Side Diff: chrome/browser/android/foreign_session_helper.cc

Issue 19874002: [Android] Expose foreign session sync related funtionalities through JNI. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fixed Patch Set 5's comments Created 7 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698