• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/bookmarks/bookmarks_bridge.h"
6 
7 #include "base/android/jni_string.h"
8 #include "base/prefs/pref_service.h"
9 #include "chrome/browser/bookmarks/bookmark_model.h"
10 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
11 #include "chrome/browser/profiles/incognito_helpers.h"
12 #include "chrome/browser/profiles/profile.h"
13 #include "chrome/browser/profiles/profile_android.h"
14 #include "chrome/browser/profiles/profile_manager.h"
15 #include "chrome/browser/signin/signin_manager.h"
16 #include "chrome/browser/signin/signin_manager_factory.h"
17 #include "chrome/common/pref_names.h"
18 #include "content/public/browser/browser_thread.h"
19 #include "jni/BookmarksBridge_jni.h"
20 
21 using base::android::AttachCurrentThread;
22 using base::android::ConvertUTF8ToJavaString;
23 using base::android::ConvertUTF16ToJavaString;
24 using base::android::ScopedJavaLocalRef;
25 using base::android::ScopedJavaGlobalRef;
26 using content::BrowserThread;
27 
28 // Should mirror constants in BookmarkBridge.java
29 static const int kBookmarkTypeNormal = 0;
30 static const int kBookmarkTypeManaged = 1;
31 static const int kBookmarkTypePartner = 2;
32 
BookmarksBridge(JNIEnv * env,jobject obj,jobject j_profile)33 BookmarksBridge::BookmarksBridge(JNIEnv* env,
34                                  jobject obj,
35                                  jobject j_profile)
36     : weak_java_ref_(env, obj),
37       bookmark_model_(NULL),
38       partner_bookmarks_shim_(NULL) {
39   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
40   profile_ = ProfileAndroid::FromProfileAndroid(j_profile);
41   bookmark_model_ = BookmarkModelFactory::GetForProfile(profile_);
42 
43   // Registers the notifications we are interested.
44   bookmark_model_->AddObserver(this);
45 
46   // Create the partner Bookmarks shim as early as possible (but don't attach).
47   partner_bookmarks_shim_ = PartnerBookmarksShim::BuildForBrowserContext(
48       chrome::GetBrowserContextRedirectedInIncognito(profile_));
49   partner_bookmarks_shim_->AddObserver(this);
50 
51   managed_bookmarks_shim_.reset(new ManagedBookmarksShim(profile_->GetPrefs()));
52   managed_bookmarks_shim_->AddObserver(this);
53 
54   NotifyIfDoneLoading();
55 
56   // Since a sync or import could have started before this class is
57   // initialized, we need to make sure that our initial state is
58   // up to date.
59   if (bookmark_model_->IsDoingExtensiveChanges())
60     ExtensiveBookmarkChangesBeginning(bookmark_model_);
61 }
62 
~BookmarksBridge()63 BookmarksBridge::~BookmarksBridge() {
64   bookmark_model_->RemoveObserver(this);
65   if (partner_bookmarks_shim_)
66     partner_bookmarks_shim_->RemoveObserver(this);
67   if (managed_bookmarks_shim_)
68     managed_bookmarks_shim_->RemoveObserver(this);
69 }
70 
Destroy(JNIEnv *,jobject)71 void BookmarksBridge::Destroy(JNIEnv*, jobject) {
72   delete this;
73 }
74 
75 // static
RegisterBookmarksBridge(JNIEnv * env)76 bool BookmarksBridge::RegisterBookmarksBridge(JNIEnv* env) {
77   return RegisterNativesImpl(env);
78 }
79 
Init(JNIEnv * env,jobject obj,jobject j_profile)80 static jlong Init(JNIEnv* env, jobject obj, jobject j_profile) {
81   BookmarksBridge* delegate = new BookmarksBridge(env, obj, j_profile);
82   return reinterpret_cast<intptr_t>(delegate);
83 }
84 
IsEditBookmarksEnabled()85 static bool IsEditBookmarksEnabled() {
86   return ProfileManager::GetLastUsedProfile()->GetPrefs()->GetBoolean(
87       prefs::kEditBookmarksEnabled);
88 }
89 
IsEditBookmarksEnabled(JNIEnv * env,jclass clazz)90 static jboolean IsEditBookmarksEnabled(JNIEnv* env, jclass clazz) {
91   return IsEditBookmarksEnabled();
92 }
93 
GetBookmarksForFolder(JNIEnv * env,jobject obj,jobject j_folder_id_obj,jobject j_callback_obj,jobject j_result_obj)94 void BookmarksBridge::GetBookmarksForFolder(JNIEnv* env,
95                                             jobject obj,
96                                             jobject j_folder_id_obj,
97                                             jobject j_callback_obj,
98                                             jobject j_result_obj) {
99   DCHECK(IsLoaded());
100   long folder_id = Java_BookmarkId_getId(env, j_folder_id_obj);
101   int type = Java_BookmarkId_getType(env, j_folder_id_obj);
102   const BookmarkNode* folder = GetFolderWithFallback(folder_id, type);
103 
104   if (!folder->is_folder() || !IsReachable(folder))
105     return;
106 
107   // Recreate the java bookmarkId object due to fallback.
108   ScopedJavaLocalRef<jobject> folder_id_obj =
109       Java_BookmarksBridge_createBookmarkId(
110           env, folder->id(), GetBookmarkType(folder));
111   j_folder_id_obj = folder_id_obj.obj();
112 
113   // If this is the Mobile bookmarks folder then add the "Managed bookmarks"
114   // folder first, so that it's the first entry.
115   if (folder == bookmark_model_->mobile_node() &&
116       managed_bookmarks_shim_->HasManagedBookmarks()) {
117     ExtractBookmarkNodeInformation(
118         managed_bookmarks_shim_->GetManagedBookmarksRoot(),
119         j_result_obj);
120   }
121   // Get the folder contents
122   for (int i = 0; i < folder->child_count(); ++i) {
123     const BookmarkNode* node = folder->GetChild(i);
124     if (!IsFolderAvailable(node))
125       continue;
126     ExtractBookmarkNodeInformation(node, j_result_obj);
127   }
128 
129   if (folder == bookmark_model_->mobile_node() &&
130       partner_bookmarks_shim_->HasPartnerBookmarks()) {
131     ExtractBookmarkNodeInformation(
132         partner_bookmarks_shim_->GetPartnerBookmarksRoot(),
133         j_result_obj);
134   }
135 
136   Java_BookmarksCallback_onBookmarksAvailable(
137       env, j_callback_obj, j_folder_id_obj, j_result_obj);
138 }
139 
GetCurrentFolderHierarchy(JNIEnv * env,jobject obj,jobject j_folder_id_obj,jobject j_callback_obj,jobject j_result_obj)140 void BookmarksBridge::GetCurrentFolderHierarchy(JNIEnv* env,
141                                                 jobject obj,
142                                                 jobject j_folder_id_obj,
143                                                 jobject j_callback_obj,
144                                                 jobject j_result_obj) {
145   DCHECK(IsLoaded());
146   long folder_id = Java_BookmarkId_getId(env, j_folder_id_obj);
147   int type = Java_BookmarkId_getType(env, j_folder_id_obj);
148   const BookmarkNode* folder = GetFolderWithFallback(folder_id, type);
149 
150   if (!folder->is_folder() || !IsReachable(folder))
151     return;
152 
153   // Recreate the java bookmarkId object due to fallback.
154   ScopedJavaLocalRef<jobject> folder_id_obj =
155       Java_BookmarksBridge_createBookmarkId(
156           env, folder->id(), GetBookmarkType(folder));
157   j_folder_id_obj = folder_id_obj.obj();
158 
159   // Get the folder heirarchy
160   const BookmarkNode* node = folder;
161   while (node) {
162     ExtractBookmarkNodeInformation(node, j_result_obj);
163     node = GetParentNode(node);
164   }
165 
166   Java_BookmarksCallback_onBookmarksFolderHierarchyAvailable(
167       env, j_callback_obj, j_folder_id_obj, j_result_obj);
168 }
169 
DeleteBookmark(JNIEnv * env,jobject obj,jobject j_bookmark_id_obj)170 void BookmarksBridge::DeleteBookmark(JNIEnv* env,
171                                      jobject obj,
172                                      jobject j_bookmark_id_obj) {
173   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
174   DCHECK(IsLoaded());
175 
176   long bookmark_id = Java_BookmarkId_getId(env, j_bookmark_id_obj);
177   int type = Java_BookmarkId_getType(env, j_bookmark_id_obj);
178   const BookmarkNode* node = GetNodeByID(bookmark_id, type);
179   if (!IsEditable(node)) {
180     NOTREACHED();
181     return;
182   }
183 
184   if (partner_bookmarks_shim_->IsPartnerBookmark(node)) {
185     partner_bookmarks_shim_->RemoveBookmark(node);
186   } else {
187     const BookmarkNode* parent_node = GetParentNode(node);
188     bookmark_model_->Remove(parent_node, parent_node->GetIndexOf(node));
189   }
190 }
191 
CreateJavaBookmark(const BookmarkNode * node)192 ScopedJavaLocalRef<jobject> BookmarksBridge::CreateJavaBookmark(
193     const BookmarkNode* node) {
194   JNIEnv* env = AttachCurrentThread();
195 
196   const BookmarkNode* parent = GetParentNode(node);
197   int64 parent_id = parent ? parent->id() : -1;
198 
199   std::string url;
200   if (node->is_url())
201     url = node->url().spec();
202 
203   return Java_BookmarksBridge_createBookmarkItem(
204       env,
205       node->id(),
206       GetBookmarkType(node),
207       ConvertUTF16ToJavaString(env, GetTitle(node)).obj(),
208       ConvertUTF8ToJavaString(env, url).obj(),
209       node->is_folder(),
210       parent_id,
211       GetBookmarkType(parent),
212       IsEditable(node));
213 }
214 
ExtractBookmarkNodeInformation(const BookmarkNode * node,jobject j_result_obj)215 void BookmarksBridge::ExtractBookmarkNodeInformation(
216     const BookmarkNode* node,
217     jobject j_result_obj) {
218   JNIEnv* env = AttachCurrentThread();
219   if (!IsReachable(node))
220     return;
221   Java_BookmarksBridge_addToList(
222       env,
223       j_result_obj,
224       CreateJavaBookmark(node).obj());
225 }
226 
GetNodeByID(long node_id,int type)227 const BookmarkNode* BookmarksBridge::GetNodeByID(long node_id,
228                                                  int type) {
229   const BookmarkNode* node;
230   if (type == kBookmarkTypeManaged) {
231     node = managed_bookmarks_shim_->GetNodeByID(
232         static_cast<int64>(node_id));
233   } else if (type == kBookmarkTypePartner) {
234     node = partner_bookmarks_shim_->GetNodeByID(
235         static_cast<int64>(node_id));
236   } else {
237     node = bookmark_model_->GetNodeByID(static_cast<int64>(node_id));
238   }
239   return node;
240 }
241 
GetFolderWithFallback(long folder_id,int type)242 const BookmarkNode* BookmarksBridge::GetFolderWithFallback(
243     long folder_id, int type) {
244   const BookmarkNode* folder = GetNodeByID(folder_id, type);
245   if (!folder || folder->type() == BookmarkNode::URL ||
246       !IsFolderAvailable(folder)) {
247     folder = bookmark_model_->mobile_node();
248   }
249   return folder;
250 }
251 
IsEditable(const BookmarkNode * node) const252 bool BookmarksBridge::IsEditable(const BookmarkNode* node) const {
253   if (!node || (node->type() != BookmarkNode::FOLDER &&
254       node->type() != BookmarkNode::URL)) {
255     return false;
256   }
257   if (!IsEditBookmarksEnabled())
258     return false;
259   if (partner_bookmarks_shim_->IsPartnerBookmark(node))
260     return true;
261   return !managed_bookmarks_shim_->IsManagedBookmark(node);
262 }
263 
GetParentNode(const BookmarkNode * node)264 const BookmarkNode* BookmarksBridge::GetParentNode(const BookmarkNode* node) {
265   DCHECK(IsLoaded());
266   if (node == managed_bookmarks_shim_->GetManagedBookmarksRoot() ||
267       node == partner_bookmarks_shim_->GetPartnerBookmarksRoot()) {
268     return bookmark_model_->mobile_node();
269   } else {
270     return node->parent();
271   }
272 }
273 
GetBookmarkType(const BookmarkNode * node)274 int BookmarksBridge::GetBookmarkType(const BookmarkNode* node) {
275   if (managed_bookmarks_shim_->IsManagedBookmark(node))
276     return kBookmarkTypeManaged;
277   else if (partner_bookmarks_shim_->IsPartnerBookmark(node))
278     return kBookmarkTypePartner;
279   else
280     return kBookmarkTypeNormal;
281 }
282 
GetTitle(const BookmarkNode * node) const283 base::string16 BookmarksBridge::GetTitle(const BookmarkNode* node) const {
284   if (partner_bookmarks_shim_->IsPartnerBookmark(node))
285     return partner_bookmarks_shim_->GetTitle(node);
286   return node->GetTitle();
287 }
288 
IsReachable(const BookmarkNode * node) const289 bool BookmarksBridge::IsReachable(const BookmarkNode* node) const {
290   if (!partner_bookmarks_shim_->IsPartnerBookmark(node))
291     return true;
292   return partner_bookmarks_shim_->IsReachable(node);
293 }
294 
IsLoaded() const295 bool BookmarksBridge::IsLoaded() const {
296   return (bookmark_model_->loaded() && partner_bookmarks_shim_->IsLoaded());
297 }
298 
IsFolderAvailable(const BookmarkNode * folder) const299 bool BookmarksBridge::IsFolderAvailable(
300     const BookmarkNode* folder) const {
301   SigninManager* signin = SigninManagerFactory::GetForProfile(
302       profile_->GetOriginalProfile());
303   return (folder->type() != BookmarkNode::BOOKMARK_BAR &&
304       folder->type() != BookmarkNode::OTHER_NODE) ||
305       (signin && !signin->GetAuthenticatedUsername().empty());
306 }
307 
NotifyIfDoneLoading()308 void BookmarksBridge::NotifyIfDoneLoading() {
309   if (!IsLoaded())
310     return;
311   JNIEnv* env = AttachCurrentThread();
312   ScopedJavaLocalRef<jobject> obj = weak_java_ref_.get(env);
313   if (obj.is_null())
314     return;
315   Java_BookmarksBridge_bookmarkModelLoaded(env, obj.obj());
316 }
317 
318 // ------------- Observer-related methods ------------- //
319 
BookmarkModelChanged()320 void BookmarksBridge::BookmarkModelChanged() {
321   if (!IsLoaded())
322     return;
323 
324   // Called when there are changes to the bookmark model. It is most
325   // likely changes to either managed or partner bookmarks.
326   JNIEnv* env = AttachCurrentThread();
327   ScopedJavaLocalRef<jobject> obj = weak_java_ref_.get(env);
328   if (obj.is_null())
329     return;
330   Java_BookmarksBridge_bookmarkModelChanged(env, obj.obj());
331 }
332 
Loaded(BookmarkModel * model,bool ids_reassigned)333 void BookmarksBridge::Loaded(BookmarkModel* model, bool ids_reassigned) {
334   NotifyIfDoneLoading();
335 }
336 
BookmarkModelBeingDeleted(BookmarkModel * model)337 void BookmarksBridge::BookmarkModelBeingDeleted(BookmarkModel* model) {
338   if (!IsLoaded())
339     return;
340 
341   JNIEnv* env = AttachCurrentThread();
342   ScopedJavaLocalRef<jobject> obj = weak_java_ref_.get(env);
343   if (obj.is_null())
344     return;
345   Java_BookmarksBridge_bookmarkModelDeleted(env, obj.obj());
346 }
347 
BookmarkNodeMoved(BookmarkModel * model,const BookmarkNode * old_parent,int old_index,const BookmarkNode * new_parent,int new_index)348 void BookmarksBridge::BookmarkNodeMoved(BookmarkModel* model,
349                                         const BookmarkNode* old_parent,
350                                         int old_index,
351                                         const BookmarkNode* new_parent,
352                                         int new_index) {
353   if (!IsLoaded())
354     return;
355 
356   JNIEnv* env = AttachCurrentThread();
357   ScopedJavaLocalRef<jobject> obj = weak_java_ref_.get(env);
358   if (obj.is_null())
359     return;
360   Java_BookmarksBridge_bookmarkNodeMoved(
361       env,
362       obj.obj(),
363       CreateJavaBookmark(old_parent).obj(),
364       old_index,
365       CreateJavaBookmark(new_parent).obj(),
366       new_index);
367 }
368 
BookmarkNodeAdded(BookmarkModel * model,const BookmarkNode * parent,int index)369 void BookmarksBridge::BookmarkNodeAdded(BookmarkModel* model,
370                                         const BookmarkNode* parent,
371                                         int index) {
372   if (!IsLoaded())
373     return;
374 
375   JNIEnv* env = AttachCurrentThread();
376   ScopedJavaLocalRef<jobject> obj = weak_java_ref_.get(env);
377   if (obj.is_null())
378     return;
379   Java_BookmarksBridge_bookmarkNodeAdded(
380       env,
381       obj.obj(),
382       CreateJavaBookmark(parent).obj(),
383       index);
384 }
385 
BookmarkNodeRemoved(BookmarkModel * model,const BookmarkNode * parent,int old_index,const BookmarkNode * node)386 void BookmarksBridge::BookmarkNodeRemoved(BookmarkModel* model,
387                                           const BookmarkNode* parent,
388                                           int old_index,
389                                           const BookmarkNode* node) {
390   if (!IsLoaded())
391     return;
392 
393   JNIEnv* env = AttachCurrentThread();
394   ScopedJavaLocalRef<jobject> obj = weak_java_ref_.get(env);
395   if (obj.is_null())
396     return;
397   Java_BookmarksBridge_bookmarkNodeRemoved(
398       env,
399       obj.obj(),
400       CreateJavaBookmark(parent).obj(),
401       old_index,
402       CreateJavaBookmark(node).obj());
403 }
404 
BookmarkNodeChanged(BookmarkModel * model,const BookmarkNode * node)405 void BookmarksBridge::BookmarkNodeChanged(BookmarkModel* model,
406                                           const BookmarkNode* node) {
407   if (!IsLoaded())
408     return;
409 
410   JNIEnv* env = AttachCurrentThread();
411   ScopedJavaLocalRef<jobject> obj = weak_java_ref_.get(env);
412   if (obj.is_null())
413     return;
414   Java_BookmarksBridge_bookmarkNodeChanged(
415       env,
416       obj.obj(),
417       CreateJavaBookmark(node).obj());
418 }
419 
BookmarkNodeChildrenReordered(BookmarkModel * model,const BookmarkNode * node)420 void BookmarksBridge::BookmarkNodeChildrenReordered(BookmarkModel* model,
421                                                     const BookmarkNode* node) {
422   if (!IsLoaded())
423     return;
424 
425   JNIEnv* env = AttachCurrentThread();
426   ScopedJavaLocalRef<jobject> obj = weak_java_ref_.get(env);
427   if (obj.is_null())
428     return;
429   Java_BookmarksBridge_bookmarkNodeChildrenReordered(
430       env,
431       obj.obj(),
432       CreateJavaBookmark(node).obj());
433 }
434 
ExtensiveBookmarkChangesBeginning(BookmarkModel * model)435 void BookmarksBridge::ExtensiveBookmarkChangesBeginning(BookmarkModel* model) {
436   if (!IsLoaded())
437     return;
438 
439   JNIEnv* env = AttachCurrentThread();
440   ScopedJavaLocalRef<jobject> obj = weak_java_ref_.get(env);
441   if (obj.is_null())
442     return;
443   Java_BookmarksBridge_extensiveBookmarkChangesBeginning(env, obj.obj());
444 }
445 
ExtensiveBookmarkChangesEnded(BookmarkModel * model)446 void BookmarksBridge::ExtensiveBookmarkChangesEnded(BookmarkModel* model) {
447   if (!IsLoaded())
448     return;
449 
450   JNIEnv* env = AttachCurrentThread();
451   ScopedJavaLocalRef<jobject> obj = weak_java_ref_.get(env);
452   if (obj.is_null())
453     return;
454   Java_BookmarksBridge_extensiveBookmarkChangesEnded(env, obj.obj());
455 }
456 
OnManagedBookmarksChanged()457 void BookmarksBridge::OnManagedBookmarksChanged() {
458   if (!IsLoaded())
459     return;
460 
461   BookmarkModelChanged();
462 }
463 
PartnerShimChanged(PartnerBookmarksShim * shim)464 void BookmarksBridge::PartnerShimChanged(PartnerBookmarksShim* shim) {
465   if (!IsLoaded())
466     return;
467 
468   BookmarkModelChanged();
469 }
470 
PartnerShimLoaded(PartnerBookmarksShim * shim)471 void BookmarksBridge::PartnerShimLoaded(PartnerBookmarksShim* shim) {
472   NotifyIfDoneLoading();
473 }
474 
ShimBeingDeleted(PartnerBookmarksShim * shim)475 void BookmarksBridge::ShimBeingDeleted(PartnerBookmarksShim* shim) {
476   partner_bookmarks_shim_ = NULL;
477 }
478