Add new certificateProvider extension API.
[chromium-blink-merge.git] / chrome / browser / android / foreign_session_helper.cc
blob7eed11fcb7ab415c26eee86326a8e6bbb25ef0ad
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.
5 #include "chrome/browser/android/foreign_session_helper.h"
7 #include <jni.h>
9 #include "base/android/jni_string.h"
10 #include "base/prefs/pref_service.h"
11 #include "base/prefs/scoped_user_pref_update.h"
12 #include "chrome/browser/android/tab_android.h"
13 #include "chrome/browser/chrome_notification_types.h"
14 #include "chrome/browser/profiles/profile_android.h"
15 #include "chrome/browser/sessions/session_restore.h"
16 #include "chrome/browser/sync/profile_sync_service.h"
17 #include "chrome/browser/sync/profile_sync_service_factory.h"
18 #include "chrome/browser/ui/android/tab_model/tab_model.h"
19 #include "chrome/browser/ui/android/tab_model/tab_model_list.h"
20 #include "chrome/common/pref_names.h"
21 #include "chrome/common/url_constants.h"
22 #include "components/sync_driver/open_tabs_ui_delegate.h"
23 #include "content/public/browser/notification_details.h"
24 #include "content/public/browser/notification_service.h"
25 #include "content/public/browser/notification_source.h"
26 #include "content/public/browser/web_contents.h"
27 #include "jni/ForeignSessionHelper_jni.h"
29 using base::android::ScopedJavaGlobalRef;
30 using base::android::ScopedJavaLocalRef;
31 using base::android::AttachCurrentThread;
32 using base::android::ConvertUTF16ToJavaString;
33 using base::android::ConvertUTF8ToJavaString;
34 using base::android::ConvertJavaStringToUTF8;
35 using sync_driver::OpenTabsUIDelegate;
36 using sync_driver::SyncedSession;
38 namespace {
40 OpenTabsUIDelegate* GetOpenTabsUIDelegate(Profile* profile) {
41 ProfileSyncService* service = ProfileSyncServiceFactory::GetInstance()->
42 GetForProfile(profile);
44 // Only return the delegate if it exists and it is done syncing sessions.
45 if (!service || !service->IsSyncActive())
46 return NULL;
48 return service->GetOpenTabsUIDelegate();
51 bool ShouldSkipTab(const sessions::SessionTab& session_tab) {
52 if (session_tab.navigations.empty())
53 return true;
55 int selected_index = session_tab.normalized_navigation_index();
56 const sessions::SerializedNavigationEntry& current_navigation =
57 session_tab.navigations.at(selected_index);
59 if (current_navigation.virtual_url().is_empty())
60 return true;
62 return false;
65 bool ShouldSkipWindow(const sessions::SessionWindow& window) {
66 for (std::vector<sessions::SessionTab*>::const_iterator tab_it =
67 window.tabs.begin(); tab_it != window.tabs.end(); ++tab_it) {
68 const sessions::SessionTab &session_tab = **tab_it;
69 if (!ShouldSkipTab(session_tab))
70 return false;
72 return true;
75 bool ShouldSkipSession(const sync_driver::SyncedSession& session) {
76 for (SyncedSession::SyncedWindowMap::const_iterator it =
77 session.windows.begin(); it != session.windows.end(); ++it) {
78 const sessions::SessionWindow &window = *(it->second);
79 if (!ShouldSkipWindow(window))
80 return false;
82 return true;
85 void CopyTabToJava(
86 JNIEnv* env,
87 const sessions::SessionTab& tab,
88 ScopedJavaLocalRef<jobject>& j_window) {
89 int selected_index = tab.normalized_navigation_index();
90 DCHECK_GE(selected_index, 0);
91 DCHECK_LT(selected_index, static_cast<int>(tab.navigations.size()));
93 const sessions::SerializedNavigationEntry& current_navigation =
94 tab.navigations.at(selected_index);
96 GURL tab_url = current_navigation.virtual_url();
98 Java_ForeignSessionHelper_pushTab(
99 env, j_window.obj(),
100 ConvertUTF8ToJavaString(env, tab_url.spec()).obj(),
101 ConvertUTF16ToJavaString(env, current_navigation.title()).obj(),
102 tab.timestamp.ToJavaTime(),
103 tab.tab_id.id());
106 void CopyWindowToJava(
107 JNIEnv* env,
108 const sessions::SessionWindow& window,
109 ScopedJavaLocalRef<jobject>& j_window) {
110 for (std::vector<sessions::SessionTab*>::const_iterator tab_it =
111 window.tabs.begin(); tab_it != window.tabs.end(); ++tab_it) {
112 const sessions::SessionTab &session_tab = **tab_it;
114 if (ShouldSkipTab(session_tab))
115 return;
117 CopyTabToJava(env, session_tab, j_window);
121 void CopySessionToJava(
122 JNIEnv* env,
123 const SyncedSession& session,
124 ScopedJavaLocalRef<jobject>& j_session) {
125 for (SyncedSession::SyncedWindowMap::const_iterator it =
126 session.windows.begin(); it != session.windows.end(); ++it) {
127 const sessions::SessionWindow &window = *(it->second);
129 if (ShouldSkipWindow(window))
130 continue;
132 ScopedJavaLocalRef<jobject> last_pushed_window;
133 last_pushed_window.Reset(
134 Java_ForeignSessionHelper_pushWindow(
135 env, j_session.obj(),
136 window.timestamp.ToJavaTime(),
137 window.window_id.id()));
139 CopyWindowToJava(env, window, last_pushed_window);
143 } // namespace
145 static jlong Init(JNIEnv* env,
146 const JavaParamRef<jclass>& clazz,
147 const JavaParamRef<jobject>& profile) {
148 ForeignSessionHelper* foreign_session_helper = new ForeignSessionHelper(
149 ProfileAndroid::FromProfileAndroid(profile));
150 return reinterpret_cast<intptr_t>(foreign_session_helper);
153 ForeignSessionHelper::ForeignSessionHelper(Profile* profile)
154 : profile_(profile) {
155 ProfileSyncService* service = ProfileSyncServiceFactory::GetInstance()->
156 GetForProfile(profile);
157 registrar_.Add(this, chrome::NOTIFICATION_SYNC_CONFIGURE_DONE,
158 content::Source<ProfileSyncService>(service));
159 registrar_.Add(this, chrome::NOTIFICATION_FOREIGN_SESSION_UPDATED,
160 content::Source<Profile>(profile));
161 registrar_.Add(this, chrome::NOTIFICATION_FOREIGN_SESSION_DISABLED,
162 content::Source<Profile>(profile));
165 ForeignSessionHelper::~ForeignSessionHelper() {
168 void ForeignSessionHelper::Destroy(JNIEnv* env, jobject obj) {
169 delete this;
172 jboolean ForeignSessionHelper::IsTabSyncEnabled(JNIEnv* env, jobject obj) {
173 ProfileSyncService* service = ProfileSyncServiceFactory::GetInstance()->
174 GetForProfile(profile_);
175 return service && service->GetActiveDataTypes().Has(syncer::PROXY_TABS);
178 void ForeignSessionHelper::TriggerSessionSync(JNIEnv* env, jobject obj) {
179 const syncer::ModelTypeSet types(syncer::SESSIONS);
180 content::NotificationService::current()->Notify(
181 chrome::NOTIFICATION_SYNC_REFRESH_LOCAL,
182 content::Source<Profile>(profile_),
183 content::Details<const syncer::ModelTypeSet>(&types));
186 void ForeignSessionHelper::SetOnForeignSessionCallback(JNIEnv* env,
187 jobject obj,
188 jobject callback) {
189 callback_.Reset(env, callback);
192 void ForeignSessionHelper::Observe(
193 int type, const content::NotificationSource& source,
194 const content::NotificationDetails& details) {
195 if (callback_.is_null())
196 return;
198 JNIEnv* env = AttachCurrentThread();
200 switch (type) {
201 case chrome::NOTIFICATION_FOREIGN_SESSION_DISABLED:
202 // Tab sync is disabled, so clean up data about collapsed sessions.
203 profile_->GetPrefs()->ClearPref(
204 prefs::kNtpCollapsedForeignSessions);
205 // Purposeful fall through.
206 case chrome::NOTIFICATION_SYNC_CONFIGURE_DONE:
207 case chrome::NOTIFICATION_FOREIGN_SESSION_UPDATED:
208 Java_ForeignSessionCallback_onUpdated(env, callback_.obj());
209 break;
210 default:
211 NOTREACHED();
215 jboolean ForeignSessionHelper::GetForeignSessions(JNIEnv* env,
216 jobject obj,
217 jobject result) {
218 OpenTabsUIDelegate* open_tabs = GetOpenTabsUIDelegate(profile_);
219 if (!open_tabs)
220 return false;
222 std::vector<const sync_driver::SyncedSession*> sessions;
223 if (!open_tabs->GetAllForeignSessions(&sessions))
224 return false;
226 // Use a pref to keep track of sessions that were collapsed by the user.
227 // To prevent the pref from accumulating stale sessions, clear it each time
228 // and only add back sessions that are still current.
229 DictionaryPrefUpdate pref_update(profile_->GetPrefs(),
230 prefs::kNtpCollapsedForeignSessions);
231 base::DictionaryValue* pref_collapsed_sessions = pref_update.Get();
232 scoped_ptr<base::DictionaryValue> collapsed_sessions(
233 pref_collapsed_sessions->DeepCopy());
234 pref_collapsed_sessions->Clear();
236 ScopedJavaLocalRef<jobject> last_pushed_session;
238 // Note: we don't own the SyncedSessions themselves.
239 for (size_t i = 0; i < sessions.size(); ++i) {
240 const sync_driver::SyncedSession& session = *(sessions[i]);
241 if (ShouldSkipSession(session))
242 continue;
244 const bool is_collapsed = collapsed_sessions->HasKey(session.session_tag);
246 if (is_collapsed)
247 pref_collapsed_sessions->SetBoolean(session.session_tag, true);
249 last_pushed_session.Reset(
250 Java_ForeignSessionHelper_pushSession(
251 env,
252 result,
253 ConvertUTF8ToJavaString(env, session.session_tag).obj(),
254 ConvertUTF8ToJavaString(env, session.session_name).obj(),
255 session.device_type,
256 session.modified_time.ToJavaTime()));
258 const std::string group_name =
259 base::FieldTrialList::FindFullName("TabSyncByRecency");
260 if (group_name == "Enabled") {
261 // Create a custom window with tabs from all windows included and ordered
262 // by recency (GetForeignSessionTabs will do ordering automatically).
263 std::vector<const sessions::SessionTab*> tabs;
264 open_tabs->GetForeignSessionTabs(session.session_tag, &tabs);
265 ScopedJavaLocalRef<jobject> last_pushed_window(
266 Java_ForeignSessionHelper_pushWindow(
267 env, last_pushed_session.obj(),
268 session.modified_time.ToJavaTime(), 0));
269 for (const sessions::SessionTab* tab : tabs) {
270 if (ShouldSkipTab(*tab))
271 continue;
272 CopyTabToJava(env, *tab, last_pushed_window);
274 } else {
275 // Push the full session, with tabs ordered by visual position.
276 CopySessionToJava(env, session, last_pushed_session);
280 return true;
283 jboolean ForeignSessionHelper::OpenForeignSessionTab(JNIEnv* env,
284 jobject obj,
285 jobject j_tab,
286 jstring session_tag,
287 jint session_tab_id,
288 jint j_disposition) {
289 OpenTabsUIDelegate* open_tabs = GetOpenTabsUIDelegate(profile_);
290 if (!open_tabs) {
291 LOG(ERROR) << "Null OpenTabsUIDelegate returned.";
292 return false;
295 const sessions::SessionTab* session_tab;
297 if (!open_tabs->GetForeignTab(ConvertJavaStringToUTF8(env, session_tag),
298 session_tab_id,
299 &session_tab)) {
300 LOG(ERROR) << "Failed to load foreign tab.";
301 return false;
304 if (session_tab->navigations.empty()) {
305 LOG(ERROR) << "Foreign tab no longer has valid navigations.";
306 return false;
309 TabAndroid* tab_android = TabAndroid::GetNativeTab(env, j_tab);
310 if (!tab_android)
311 return false;
312 content::WebContents* web_contents = tab_android->web_contents();
313 if (!web_contents)
314 return false;
316 WindowOpenDisposition disposition =
317 static_cast<WindowOpenDisposition>(j_disposition);
318 SessionRestore::RestoreForeignSessionTab(web_contents,
319 *session_tab,
320 disposition);
322 return true;
325 void ForeignSessionHelper::DeleteForeignSession(JNIEnv* env, jobject obj,
326 jstring session_tag) {
327 OpenTabsUIDelegate* open_tabs = GetOpenTabsUIDelegate(profile_);
328 if (open_tabs)
329 open_tabs->DeleteForeignSession(ConvertJavaStringToUTF8(env, session_tag));
332 // static
333 bool ForeignSessionHelper::RegisterForeignSessionHelper(JNIEnv* env) {
334 return RegisterNativesImpl(env);