Check USB device path access when prompting users to select a device.
[chromium-blink-merge.git] / chrome / browser / android / foreign_session_helper.cc
blobd195900b3c97b69e1380378114b0440afa9c93e6
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/open_tabs_ui_delegate.h"
17 #include "chrome/browser/sync/profile_sync_service.h"
18 #include "chrome/browser/sync/profile_sync_service_factory.h"
19 #include "chrome/browser/ui/android/tab_model/tab_model.h"
20 #include "chrome/browser/ui/android/tab_model/tab_model_list.h"
21 #include "chrome/common/pref_names.h"
22 #include "chrome/common/url_constants.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 browser_sync::OpenTabsUIDelegate;
36 using browser_sync::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->SyncActive())
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 browser_sync::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 CopyTabsToJava(
86 JNIEnv* env,
87 const sessions::SessionWindow& window,
88 ScopedJavaLocalRef<jobject>& j_window) {
89 for (std::vector<sessions::SessionTab*>::const_iterator tab_it =
90 window.tabs.begin(); tab_it != window.tabs.end(); ++tab_it) {
91 const sessions::SessionTab &session_tab = **tab_it;
93 if (ShouldSkipTab(session_tab))
94 continue;
96 int selected_index = session_tab.normalized_navigation_index();
97 DCHECK(selected_index >= 0);
98 DCHECK(selected_index < static_cast<int>(session_tab.navigations.size()));
100 const ::sessions::SerializedNavigationEntry& current_navigation =
101 session_tab.navigations.at(selected_index);
103 GURL tab_url = current_navigation.virtual_url();
105 Java_ForeignSessionHelper_pushTab(
106 env, j_window.obj(),
107 ConvertUTF8ToJavaString(env, tab_url.spec()).obj(),
108 ConvertUTF16ToJavaString(env, current_navigation.title()).obj(),
109 session_tab.timestamp.ToJavaTime(),
110 session_tab.tab_id.id());
114 void CopyWindowsToJava(
115 JNIEnv* env,
116 const SyncedSession& session,
117 ScopedJavaLocalRef<jobject>& j_session) {
118 for (SyncedSession::SyncedWindowMap::const_iterator it =
119 session.windows.begin(); it != session.windows.end(); ++it) {
120 const sessions::SessionWindow &window = *(it->second);
122 if (ShouldSkipWindow(window))
123 continue;
125 ScopedJavaLocalRef<jobject> last_pushed_window;
126 last_pushed_window.Reset(
127 Java_ForeignSessionHelper_pushWindow(
128 env, j_session.obj(),
129 window.timestamp.ToJavaTime(),
130 window.window_id.id()));
132 CopyTabsToJava(env, window, last_pushed_window);
136 } // namespace
138 static jlong Init(JNIEnv* env, jclass clazz, jobject profile) {
139 ForeignSessionHelper* foreign_session_helper = new ForeignSessionHelper(
140 ProfileAndroid::FromProfileAndroid(profile));
141 return reinterpret_cast<intptr_t>(foreign_session_helper);
144 ForeignSessionHelper::ForeignSessionHelper(Profile* profile)
145 : profile_(profile) {
146 ProfileSyncService* service = ProfileSyncServiceFactory::GetInstance()->
147 GetForProfile(profile);
148 registrar_.Add(this, chrome::NOTIFICATION_SYNC_CONFIGURE_DONE,
149 content::Source<ProfileSyncService>(service));
150 registrar_.Add(this, chrome::NOTIFICATION_FOREIGN_SESSION_UPDATED,
151 content::Source<Profile>(profile));
152 registrar_.Add(this, chrome::NOTIFICATION_FOREIGN_SESSION_DISABLED,
153 content::Source<Profile>(profile));
156 ForeignSessionHelper::~ForeignSessionHelper() {
159 void ForeignSessionHelper::Destroy(JNIEnv* env, jobject obj) {
160 delete this;
163 jboolean ForeignSessionHelper::IsTabSyncEnabled(JNIEnv* env, jobject obj) {
164 ProfileSyncService* service = ProfileSyncServiceFactory::GetInstance()->
165 GetForProfile(profile_);
166 return service && service->GetActiveDataTypes().Has(syncer::PROXY_TABS);
169 void ForeignSessionHelper::TriggerSessionSync(JNIEnv* env, jobject obj) {
170 const syncer::ModelTypeSet types(syncer::SESSIONS);
171 content::NotificationService::current()->Notify(
172 chrome::NOTIFICATION_SYNC_REFRESH_LOCAL,
173 content::Source<Profile>(profile_),
174 content::Details<const syncer::ModelTypeSet>(&types));
177 void ForeignSessionHelper::SetOnForeignSessionCallback(JNIEnv* env,
178 jobject obj,
179 jobject callback) {
180 callback_.Reset(env, callback);
183 void ForeignSessionHelper::Observe(
184 int type, const content::NotificationSource& source,
185 const content::NotificationDetails& details) {
186 if (callback_.is_null())
187 return;
189 JNIEnv* env = AttachCurrentThread();
191 switch (type) {
192 case chrome::NOTIFICATION_FOREIGN_SESSION_DISABLED:
193 // Tab sync is disabled, so clean up data about collapsed sessions.
194 profile_->GetPrefs()->ClearPref(
195 prefs::kNtpCollapsedForeignSessions);
196 // Purposeful fall through.
197 case chrome::NOTIFICATION_SYNC_CONFIGURE_DONE:
198 case chrome::NOTIFICATION_FOREIGN_SESSION_UPDATED:
199 Java_ForeignSessionCallback_onUpdated(env, callback_.obj());
200 break;
201 default:
202 NOTREACHED();
206 jboolean ForeignSessionHelper::GetForeignSessions(JNIEnv* env,
207 jobject obj,
208 jobject result) {
209 OpenTabsUIDelegate* open_tabs = GetOpenTabsUIDelegate(profile_);
210 if (!open_tabs)
211 return false;
213 std::vector<const browser_sync::SyncedSession*> sessions;
214 if (!open_tabs->GetAllForeignSessions(&sessions))
215 return false;
217 // Use a pref to keep track of sessions that were collapsed by the user.
218 // To prevent the pref from accumulating stale sessions, clear it each time
219 // and only add back sessions that are still current.
220 DictionaryPrefUpdate pref_update(profile_->GetPrefs(),
221 prefs::kNtpCollapsedForeignSessions);
222 base::DictionaryValue* pref_collapsed_sessions = pref_update.Get();
223 scoped_ptr<base::DictionaryValue> collapsed_sessions(
224 pref_collapsed_sessions->DeepCopy());
225 pref_collapsed_sessions->Clear();
227 ScopedJavaLocalRef<jobject> last_pushed_session;
228 ScopedJavaLocalRef<jobject> last_pushed_window;
230 // Note: we don't own the SyncedSessions themselves.
231 for (size_t i = 0; i < sessions.size(); ++i) {
232 const browser_sync::SyncedSession &session = *(sessions[i]);
233 if (ShouldSkipSession(session))
234 continue;
236 const bool is_collapsed = collapsed_sessions->HasKey(session.session_tag);
238 if (is_collapsed)
239 pref_collapsed_sessions->SetBoolean(session.session_tag, true);
241 last_pushed_session.Reset(
242 Java_ForeignSessionHelper_pushSession(
243 env,
244 result,
245 ConvertUTF8ToJavaString(env, session.session_tag).obj(),
246 ConvertUTF8ToJavaString(env, session.session_name).obj(),
247 session.device_type,
248 session.modified_time.ToJavaTime()));
250 CopyWindowsToJava(env, session, last_pushed_session);
253 return true;
256 jboolean ForeignSessionHelper::OpenForeignSessionTab(JNIEnv* env,
257 jobject obj,
258 jobject j_tab,
259 jstring session_tag,
260 jint session_tab_id,
261 jint j_disposition) {
262 OpenTabsUIDelegate* open_tabs = GetOpenTabsUIDelegate(profile_);
263 if (!open_tabs) {
264 LOG(ERROR) << "Null OpenTabsUIDelegate returned.";
265 return false;
268 const sessions::SessionTab* session_tab;
270 if (!open_tabs->GetForeignTab(ConvertJavaStringToUTF8(env, session_tag),
271 session_tab_id,
272 &session_tab)) {
273 LOG(ERROR) << "Failed to load foreign tab.";
274 return false;
277 if (session_tab->navigations.empty()) {
278 LOG(ERROR) << "Foreign tab no longer has valid navigations.";
279 return false;
282 TabAndroid* tab_android = TabAndroid::GetNativeTab(env, j_tab);
283 if (!tab_android)
284 return false;
285 content::WebContents* web_contents = tab_android->web_contents();
286 if (!web_contents)
287 return false;
289 WindowOpenDisposition disposition =
290 static_cast<WindowOpenDisposition>(j_disposition);
291 SessionRestore::RestoreForeignSessionTab(web_contents,
292 *session_tab,
293 disposition);
295 return true;
298 void ForeignSessionHelper::DeleteForeignSession(JNIEnv* env, jobject obj,
299 jstring session_tag) {
300 OpenTabsUIDelegate* open_tabs = GetOpenTabsUIDelegate(profile_);
301 if (open_tabs)
302 open_tabs->DeleteForeignSession(ConvertJavaStringToUTF8(env, session_tag));
305 // static
306 bool ForeignSessionHelper::RegisterForeignSessionHelper(JNIEnv* env) {
307 return RegisterNativesImpl(env);