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/bookmarks/bookmarks_bridge.h"
7 #include "base/android/jni_string.h"
8 #include "base/prefs/pref_service.h"
9 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
10 #include "chrome/browser/profiles/incognito_helpers.h"
11 #include "chrome/browser/profiles/profile.h"
12 #include "chrome/browser/profiles/profile_android.h"
13 #include "chrome/browser/profiles/profile_manager.h"
14 #include "chrome/browser/signin/signin_manager_factory.h"
15 #include "chrome/common/pref_names.h"
16 #include "components/bookmarks/browser/bookmark_model.h"
17 #include "components/bookmarks/browser/bookmark_utils.h"
18 #include "components/signin/core/browser/signin_manager.h"
19 #include "content/public/browser/browser_thread.h"
20 #include "jni/BookmarksBridge_jni.h"
22 using base::android::AttachCurrentThread
;
23 using base::android::ConvertUTF8ToJavaString
;
24 using base::android::ConvertUTF16ToJavaString
;
25 using base::android::ScopedJavaLocalRef
;
26 using base::android::ScopedJavaGlobalRef
;
27 using content::BrowserThread
;
29 // Should mirror constants in BookmarkBridge.java
30 static const int kBookmarkTypeNormal
= 0;
31 static const int kBookmarkTypeManaged
= 1;
32 static const int kBookmarkTypePartner
= 2;
34 BookmarksBridge::BookmarksBridge(JNIEnv
* env
,
37 : weak_java_ref_(env
, obj
),
38 bookmark_model_(NULL
),
39 partner_bookmarks_shim_(NULL
) {
40 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
41 profile_
= ProfileAndroid::FromProfileAndroid(j_profile
);
42 bookmark_model_
= BookmarkModelFactory::GetForProfile(profile_
);
44 // Registers the notifications we are interested.
45 bookmark_model_
->AddObserver(this);
47 // Create the partner Bookmarks shim as early as possible (but don't attach).
48 partner_bookmarks_shim_
= PartnerBookmarksShim::BuildForBrowserContext(
49 chrome::GetBrowserContextRedirectedInIncognito(profile_
));
50 partner_bookmarks_shim_
->AddObserver(this);
52 managed_bookmarks_shim_
.reset(new ManagedBookmarksShim(profile_
->GetPrefs()));
53 managed_bookmarks_shim_
->AddObserver(this);
55 NotifyIfDoneLoading();
57 // Since a sync or import could have started before this class is
58 // initialized, we need to make sure that our initial state is
60 if (bookmark_model_
->IsDoingExtensiveChanges())
61 ExtensiveBookmarkChangesBeginning(bookmark_model_
);
64 BookmarksBridge::~BookmarksBridge() {
65 bookmark_model_
->RemoveObserver(this);
66 if (partner_bookmarks_shim_
)
67 partner_bookmarks_shim_
->RemoveObserver(this);
68 if (managed_bookmarks_shim_
)
69 managed_bookmarks_shim_
->RemoveObserver(this);
72 void BookmarksBridge::Destroy(JNIEnv
*, jobject
) {
77 bool BookmarksBridge::RegisterBookmarksBridge(JNIEnv
* env
) {
78 return RegisterNativesImpl(env
);
81 static jlong
Init(JNIEnv
* env
, jobject obj
, jobject j_profile
) {
82 BookmarksBridge
* delegate
= new BookmarksBridge(env
, obj
, j_profile
);
83 return reinterpret_cast<intptr_t>(delegate
);
86 static bool IsEditBookmarksEnabled() {
87 return ProfileManager::GetLastUsedProfile()->GetPrefs()->GetBoolean(
88 prefs::kEditBookmarksEnabled
);
91 static jboolean
IsEditBookmarksEnabled(JNIEnv
* env
, jclass clazz
) {
92 return IsEditBookmarksEnabled();
95 void BookmarksBridge::GetBookmarksForFolder(JNIEnv
* env
,
97 jobject j_folder_id_obj
,
98 jobject j_callback_obj
,
99 jobject j_result_obj
) {
101 long folder_id
= Java_BookmarkId_getId(env
, j_folder_id_obj
);
102 int type
= Java_BookmarkId_getType(env
, j_folder_id_obj
);
103 const BookmarkNode
* folder
= GetFolderWithFallback(folder_id
, type
);
105 if (!folder
->is_folder() || !IsReachable(folder
))
108 // Recreate the java bookmarkId object due to fallback.
109 ScopedJavaLocalRef
<jobject
> folder_id_obj
=
110 Java_BookmarksBridge_createBookmarkId(
111 env
, folder
->id(), GetBookmarkType(folder
));
112 j_folder_id_obj
= folder_id_obj
.obj();
114 // If this is the Mobile bookmarks folder then add the "Managed bookmarks"
115 // folder first, so that it's the first entry.
116 if (folder
== bookmark_model_
->mobile_node() &&
117 managed_bookmarks_shim_
->HasManagedBookmarks()) {
118 ExtractBookmarkNodeInformation(
119 managed_bookmarks_shim_
->GetManagedBookmarksRoot(),
122 // Get the folder contents
123 for (int i
= 0; i
< folder
->child_count(); ++i
) {
124 const BookmarkNode
* node
= folder
->GetChild(i
);
125 if (!IsFolderAvailable(node
))
127 ExtractBookmarkNodeInformation(node
, j_result_obj
);
130 if (folder
== bookmark_model_
->mobile_node() &&
131 partner_bookmarks_shim_
->HasPartnerBookmarks()) {
132 ExtractBookmarkNodeInformation(
133 partner_bookmarks_shim_
->GetPartnerBookmarksRoot(),
137 Java_BookmarksCallback_onBookmarksAvailable(
138 env
, j_callback_obj
, j_folder_id_obj
, j_result_obj
);
141 void BookmarksBridge::GetCurrentFolderHierarchy(JNIEnv
* env
,
143 jobject j_folder_id_obj
,
144 jobject j_callback_obj
,
145 jobject j_result_obj
) {
147 long folder_id
= Java_BookmarkId_getId(env
, j_folder_id_obj
);
148 int type
= Java_BookmarkId_getType(env
, j_folder_id_obj
);
149 const BookmarkNode
* folder
= GetFolderWithFallback(folder_id
, type
);
151 if (!folder
->is_folder() || !IsReachable(folder
))
154 // Recreate the java bookmarkId object due to fallback.
155 ScopedJavaLocalRef
<jobject
> folder_id_obj
=
156 Java_BookmarksBridge_createBookmarkId(
157 env
, folder
->id(), GetBookmarkType(folder
));
158 j_folder_id_obj
= folder_id_obj
.obj();
160 // Get the folder heirarchy
161 const BookmarkNode
* node
= folder
;
163 ExtractBookmarkNodeInformation(node
, j_result_obj
);
164 node
= GetParentNode(node
);
167 Java_BookmarksCallback_onBookmarksFolderHierarchyAvailable(
168 env
, j_callback_obj
, j_folder_id_obj
, j_result_obj
);
171 void BookmarksBridge::DeleteBookmark(JNIEnv
* env
,
173 jobject j_bookmark_id_obj
) {
174 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
177 long bookmark_id
= Java_BookmarkId_getId(env
, j_bookmark_id_obj
);
178 int type
= Java_BookmarkId_getType(env
, j_bookmark_id_obj
);
179 const BookmarkNode
* node
= GetNodeByID(bookmark_id
, type
);
180 if (!IsEditable(node
)) {
185 if (partner_bookmarks_shim_
->IsPartnerBookmark(node
)) {
186 partner_bookmarks_shim_
->RemoveBookmark(node
);
188 const BookmarkNode
* parent_node
= GetParentNode(node
);
189 bookmark_model_
->Remove(parent_node
, parent_node
->GetIndexOf(node
));
193 void BookmarksBridge::MoveBookmark(JNIEnv
* env
,
195 jobject j_bookmark_id_obj
,
196 jobject j_parent_id_obj
,
198 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
201 long bookmark_id
= Java_BookmarkId_getId(env
, j_bookmark_id_obj
);
202 int type
= Java_BookmarkId_getType(env
, j_bookmark_id_obj
);
203 const BookmarkNode
* node
= GetNodeByID(bookmark_id
, type
);
204 if (!IsEditable(node
)) {
208 bookmark_id
= Java_BookmarkId_getId(env
, j_parent_id_obj
);
209 type
= Java_BookmarkId_getType(env
, j_parent_id_obj
);
210 const BookmarkNode
* new_parent_node
= GetNodeByID(bookmark_id
, type
);
211 bookmark_model_
->Move(node
, new_parent_node
, index
);
214 ScopedJavaLocalRef
<jobject
> BookmarksBridge::CreateJavaBookmark(
215 const BookmarkNode
* node
) {
216 JNIEnv
* env
= AttachCurrentThread();
218 const BookmarkNode
* parent
= GetParentNode(node
);
219 int64 parent_id
= parent
? parent
->id() : -1;
223 url
= node
->url().spec();
225 return Java_BookmarksBridge_createBookmarkItem(
228 GetBookmarkType(node
),
229 ConvertUTF16ToJavaString(env
, GetTitle(node
)).obj(),
230 ConvertUTF8ToJavaString(env
, url
).obj(),
233 GetBookmarkType(parent
),
237 void BookmarksBridge::ExtractBookmarkNodeInformation(const BookmarkNode
* node
,
238 jobject j_result_obj
) {
239 JNIEnv
* env
= AttachCurrentThread();
240 if (!IsReachable(node
))
242 Java_BookmarksBridge_addToList(
243 env
, j_result_obj
, CreateJavaBookmark(node
).obj());
246 const BookmarkNode
* BookmarksBridge::GetNodeByID(long node_id
, int type
) {
247 const BookmarkNode
* node
;
248 if (type
== kBookmarkTypeManaged
) {
249 node
= managed_bookmarks_shim_
->GetNodeByID(
250 static_cast<int64
>(node_id
));
251 } else if (type
== kBookmarkTypePartner
) {
252 node
= partner_bookmarks_shim_
->GetNodeByID(
253 static_cast<int64
>(node_id
));
255 node
= GetBookmarkNodeByID(bookmark_model_
, static_cast<int64
>(node_id
));
260 const BookmarkNode
* BookmarksBridge::GetFolderWithFallback(long folder_id
,
262 const BookmarkNode
* folder
= GetNodeByID(folder_id
, type
);
263 if (!folder
|| folder
->type() == BookmarkNode::URL
||
264 !IsFolderAvailable(folder
)) {
265 folder
= bookmark_model_
->mobile_node();
270 bool BookmarksBridge::IsEditable(const BookmarkNode
* node
) const {
271 if (!node
|| (node
->type() != BookmarkNode::FOLDER
&&
272 node
->type() != BookmarkNode::URL
)) {
275 if (!IsEditBookmarksEnabled())
277 if (partner_bookmarks_shim_
->IsPartnerBookmark(node
))
278 return partner_bookmarks_shim_
->IsEditable(node
);
279 return !managed_bookmarks_shim_
->IsManagedBookmark(node
);
282 const BookmarkNode
* BookmarksBridge::GetParentNode(const BookmarkNode
* node
) {
284 if (node
== managed_bookmarks_shim_
->GetManagedBookmarksRoot() ||
285 node
== partner_bookmarks_shim_
->GetPartnerBookmarksRoot()) {
286 return bookmark_model_
->mobile_node();
288 return node
->parent();
292 int BookmarksBridge::GetBookmarkType(const BookmarkNode
* node
) {
293 if (managed_bookmarks_shim_
->IsManagedBookmark(node
))
294 return kBookmarkTypeManaged
;
295 else if (partner_bookmarks_shim_
->IsPartnerBookmark(node
))
296 return kBookmarkTypePartner
;
298 return kBookmarkTypeNormal
;
301 base::string16
BookmarksBridge::GetTitle(const BookmarkNode
* node
) const {
302 if (partner_bookmarks_shim_
->IsPartnerBookmark(node
))
303 return partner_bookmarks_shim_
->GetTitle(node
);
304 return node
->GetTitle();
307 bool BookmarksBridge::IsReachable(const BookmarkNode
* node
) const {
308 if (!partner_bookmarks_shim_
->IsPartnerBookmark(node
))
310 return partner_bookmarks_shim_
->IsReachable(node
);
313 bool BookmarksBridge::IsLoaded() const {
314 return (bookmark_model_
->loaded() && partner_bookmarks_shim_
->IsLoaded());
317 bool BookmarksBridge::IsFolderAvailable(
318 const BookmarkNode
* folder
) const {
319 SigninManager
* signin
= SigninManagerFactory::GetForProfile(
320 profile_
->GetOriginalProfile());
321 return (folder
->type() != BookmarkNode::BOOKMARK_BAR
&&
322 folder
->type() != BookmarkNode::OTHER_NODE
) ||
323 (signin
&& !signin
->GetAuthenticatedUsername().empty());
326 void BookmarksBridge::NotifyIfDoneLoading() {
329 JNIEnv
* env
= AttachCurrentThread();
330 ScopedJavaLocalRef
<jobject
> obj
= weak_java_ref_
.get(env
);
333 Java_BookmarksBridge_bookmarkModelLoaded(env
, obj
.obj());
336 // ------------- Observer-related methods ------------- //
338 void BookmarksBridge::BookmarkModelChanged() {
342 // Called when there are changes to the bookmark model. It is most
343 // likely changes to either managed or partner bookmarks.
344 JNIEnv
* env
= AttachCurrentThread();
345 ScopedJavaLocalRef
<jobject
> obj
= weak_java_ref_
.get(env
);
348 Java_BookmarksBridge_bookmarkModelChanged(env
, obj
.obj());
351 void BookmarksBridge::BookmarkModelLoaded(BookmarkModel
* model
,
352 bool ids_reassigned
) {
353 NotifyIfDoneLoading();
356 void BookmarksBridge::BookmarkModelBeingDeleted(BookmarkModel
* model
) {
360 JNIEnv
* env
= AttachCurrentThread();
361 ScopedJavaLocalRef
<jobject
> obj
= weak_java_ref_
.get(env
);
364 Java_BookmarksBridge_bookmarkModelDeleted(env
, obj
.obj());
367 void BookmarksBridge::BookmarkNodeMoved(BookmarkModel
* model
,
368 const BookmarkNode
* old_parent
,
370 const BookmarkNode
* new_parent
,
375 JNIEnv
* env
= AttachCurrentThread();
376 ScopedJavaLocalRef
<jobject
> obj
= weak_java_ref_
.get(env
);
379 Java_BookmarksBridge_bookmarkNodeMoved(
382 CreateJavaBookmark(old_parent
).obj(),
384 CreateJavaBookmark(new_parent
).obj(),
388 void BookmarksBridge::BookmarkNodeAdded(BookmarkModel
* model
,
389 const BookmarkNode
* parent
,
394 JNIEnv
* env
= AttachCurrentThread();
395 ScopedJavaLocalRef
<jobject
> obj
= weak_java_ref_
.get(env
);
398 Java_BookmarksBridge_bookmarkNodeAdded(
401 CreateJavaBookmark(parent
).obj(),
405 void BookmarksBridge::BookmarkNodeRemoved(BookmarkModel
* model
,
406 const BookmarkNode
* parent
,
408 const BookmarkNode
* node
,
409 const std::set
<GURL
>& removed_urls
) {
413 JNIEnv
* env
= AttachCurrentThread();
414 ScopedJavaLocalRef
<jobject
> obj
= weak_java_ref_
.get(env
);
417 Java_BookmarksBridge_bookmarkNodeRemoved(
420 CreateJavaBookmark(parent
).obj(),
422 CreateJavaBookmark(node
).obj());
425 void BookmarksBridge::BookmarkNodeChanged(BookmarkModel
* model
,
426 const BookmarkNode
* node
) {
430 JNIEnv
* env
= AttachCurrentThread();
431 ScopedJavaLocalRef
<jobject
> obj
= weak_java_ref_
.get(env
);
434 Java_BookmarksBridge_bookmarkNodeChanged(
437 CreateJavaBookmark(node
).obj());
440 void BookmarksBridge::BookmarkNodeChildrenReordered(BookmarkModel
* model
,
441 const BookmarkNode
* node
) {
445 JNIEnv
* env
= AttachCurrentThread();
446 ScopedJavaLocalRef
<jobject
> obj
= weak_java_ref_
.get(env
);
449 Java_BookmarksBridge_bookmarkNodeChildrenReordered(
452 CreateJavaBookmark(node
).obj());
455 void BookmarksBridge::ExtensiveBookmarkChangesBeginning(BookmarkModel
* model
) {
459 JNIEnv
* env
= AttachCurrentThread();
460 ScopedJavaLocalRef
<jobject
> obj
= weak_java_ref_
.get(env
);
463 Java_BookmarksBridge_extensiveBookmarkChangesBeginning(env
, obj
.obj());
466 void BookmarksBridge::ExtensiveBookmarkChangesEnded(BookmarkModel
* model
) {
470 JNIEnv
* env
= AttachCurrentThread();
471 ScopedJavaLocalRef
<jobject
> obj
= weak_java_ref_
.get(env
);
474 Java_BookmarksBridge_extensiveBookmarkChangesEnded(env
, obj
.obj());
477 void BookmarksBridge::OnManagedBookmarksChanged() {
481 BookmarkModelChanged();
484 void BookmarksBridge::PartnerShimChanged(PartnerBookmarksShim
* shim
) {
488 BookmarkModelChanged();
491 void BookmarksBridge::PartnerShimLoaded(PartnerBookmarksShim
* shim
) {
492 NotifyIfDoneLoading();
495 void BookmarksBridge::ShimBeingDeleted(PartnerBookmarksShim
* shim
) {
496 partner_bookmarks_shim_
= NULL
;