Skip to content

Commit

Permalink
[Enhanced Bookmark]Upstream image fetching code in android
Browse files Browse the repository at this point in the history
This CL added the image fetching code that previously lived in clank private repository.

Also I moved android enhanced_bookmark_bridge from
chrome/browser/android/enhanced_bookmarks/ to chrome/browser/enhanced_bookmarks/android,
since the latter is a more unified place to put all files in.(I deleted the
android/enhanced_bookmarks folder).

Last but not least, I made some small changes to the internal implementation of
bookmark_image_service, making it more readable.

The previously private code can be found in code search:
https://cs.corp.google.com/#clankium/src/clank/native/framework/chrome/enhanced_bookmarks/

Downstream CL: https://chrome-internal-review.googlesource.com/#/c/195438/
BUG=454623

Review URL: https://codereview.chromium.org/899653003

Cr-Commit-Position: refs/heads/master@{#314872}
  • Loading branch information
jollycopper authored and Commit bot committed Feb 5, 2015
1 parent f8b95b1 commit 566c432
Show file tree
Hide file tree
Showing 15 changed files with 600 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@

package org.chromium.chrome.browser;

import android.graphics.Bitmap;
import android.util.LruCache;
import android.util.Pair;

import org.chromium.base.CalledByNative;
import org.chromium.base.JNINamespace;
import org.chromium.base.ObserverList;
Expand All @@ -13,6 +17,7 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

/**
* Access gate to C++ side enhanced bookmarks functionalities.
Expand All @@ -25,6 +30,22 @@ public final class EnhancedBookmarksBridge {
private final ObserverList<SearchServiceObserver> mSearchObservers =
new ObserverList<SearchServiceObserver>();

private LruCache<String, Pair<String, Bitmap>> mSalientImageCache;

/**
* Interface for getting result back from SalientImageForUrl function.
*/
public interface SalientImageCallback {
/**
* Callback method for fetching salient image.
* @param image Salient image. This can be null if the image cannot be found.
* @param imageUrl Url of the image. Note this is not the same as the url of the website
* containing the image.
*/
@CalledByNative("SalientImageCallback")
void onSalientImageReady(Bitmap image, String imageUrl);
}

/**
* Interface to provide consumers notifications to changes in clusters
*/
Expand All @@ -46,6 +67,19 @@ public interface SearchServiceObserver {
void onSearchResultsReturned();
}

public EnhancedBookmarksBridge(Profile profile, int maxCacheSize) {
this(profile);
// Do not initialize LruCache if cache size is set to 0.
if (maxCacheSize != 0) {
mSalientImageCache = new LruCache<String, Pair<String, Bitmap>>(maxCacheSize) {
@Override
protected int sizeOf(String key, Pair<String, Bitmap> urlImage) {
return urlImage.first.length() + urlImage.second.getByteCount();
}
};
}
}

public EnhancedBookmarksBridge(Profile profile) {
mNativeEnhancedBookmarksBridge = nativeInit(profile);
}
Expand All @@ -54,6 +88,14 @@ public void destroy() {
assert mNativeEnhancedBookmarksBridge != 0;
nativeDestroy(mNativeEnhancedBookmarksBridge);
mNativeEnhancedBookmarksBridge = 0;

if (mSalientImageCache != null) {
for (Map.Entry<String, Pair<String, Bitmap>> entry :
mSalientImageCache.snapshot().entrySet()) {
entry.getValue().second.recycle();
}
mSalientImageCache.evictAll();
}
}

/**
Expand Down Expand Up @@ -170,6 +212,39 @@ public void removeSearchObserver(SearchServiceObserver observer) {
mSearchObservers.removeObserver(observer);
}

/**
* Request bookmark salient image for the given URL. Please refer to
* |BookmarkImageService::SalientImageForUrl|.
* @return True if this method is executed synchronously. False if
* {@link SalientImageCallback#onSalientImageReady(Bitmap, String)} is called later
* (asynchronously).
*/
public boolean salientImageForUrl(final String url, final SalientImageCallback callback) {
assert callback != null;
SalientImageCallback callbackWrapper = callback;

if (mSalientImageCache != null) {
Pair<String, Bitmap> cached = mSalientImageCache.get(url);
if (cached != null) {
callback.onSalientImageReady(cached.second, cached.first);
return true;
}

callbackWrapper = new SalientImageCallback() {
@Override
public void onSalientImageReady(Bitmap image, String imageUrl) {
if (image != null) {
mSalientImageCache.put(url, new Pair<String, Bitmap>(imageUrl, image));
}
callback.onSalientImageReady(image, imageUrl);
}
};
}

nativeSalientImageForUrl(mNativeEnhancedBookmarksBridge, url, callbackWrapper);
return false;
}

/**
* Get all filters associated with the given bookmark.
*
Expand Down Expand Up @@ -235,4 +310,6 @@ private native void nativeMoveBookmark(long nativeEnhancedBookmarksBridge,
private native BookmarkId nativeAddBookmark(long nativeEnhancedBookmarksBridge,
BookmarkId parent, int index, String title, String url);
private native void nativeSendSearchRequest(long nativeEnhancedBookmarksBridge, String query);
private static native void nativeSalientImageForUrl(long nativeEnhancedBookmarksBridge,
String url, SalientImageCallback callback);
}
2 changes: 1 addition & 1 deletion chrome/browser/android/chrome_jni_registrar.cc
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
#include "chrome/browser/android/dev_tools_server.h"
#include "chrome/browser/android/dom_distiller/feedback_reporter_android.h"
#include "chrome/browser/android/download/chrome_download_delegate.h"
#include "chrome/browser/android/enhanced_bookmarks/enhanced_bookmarks_bridge.h"
#include "chrome/browser/android/favicon_helper.h"
#include "chrome/browser/android/feature_utilities.h"
#include "chrome/browser/android/find_in_page/find_in_page_bridge.h"
Expand Down Expand Up @@ -57,6 +56,7 @@
#include "chrome/browser/autofill/android/personal_data_manager_android.h"
#include "chrome/browser/dom_distiller/dom_distiller_service_factory_android.h"
#include "chrome/browser/dom_distiller/tab_utils_android.h"
#include "chrome/browser/enhanced_bookmarks/android/enhanced_bookmarks_bridge.h"
#include "chrome/browser/history/android/sqlite_cursor.h"
#include "chrome/browser/invalidation/invalidation_service_factory_android.h"
#include "chrome/browser/lifetime/application_lifetime_android.h"
Expand Down
1 change: 0 additions & 1 deletion chrome/browser/android/enhanced_bookmarks/OWNERS

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,217 @@
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/json/json_parser.h"
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
#include "chrome/browser/bitmap_fetcher/bitmap_fetcher.h"
#include "chrome/browser/enhanced_bookmarks/android/bookmark_image_service_android.h"
#include "chrome/browser/enhanced_bookmarks/enhanced_bookmark_model_factory.h"
#include "chrome/grit/browser_resources.h"
#include "components/bookmarks/browser/bookmark_model.h"
#include "components/enhanced_bookmarks/enhanced_bookmark_model.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/navigation_entry.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/referrer.h"
#include "net/base/load_flags.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/image/image_skia.h"

using content::Referrer;
using bookmarks::BookmarkNode;

namespace enhanced_bookmarks {

BookmarkImageServiceAndroid::BookmarkImageServiceAndroid(
content::BrowserContext* browserContext)
: BookmarkImageService(
browserContext->GetPath(),
EnhancedBookmarkModelFactory::GetForBrowserContext(browserContext),
make_scoped_refptr(content::BrowserThread::GetBlockingPool())),
browser_context_(browserContext) {
}

void BookmarkImageServiceAndroid::RetrieveSalientImage(
const GURL& page_url,
const GURL& image_url,
const std::string& referrer,
net::URLRequest::ReferrerPolicy referrer_policy,
bool update_bookmark) {
const BookmarkNode* bookmark =
enhanced_bookmark_model_->bookmark_model()
->GetMostRecentlyAddedUserNodeForURL(page_url);
if (!bookmark || !image_url.is_valid()) {
ProcessNewImage(page_url, update_bookmark, gfx::Image(), image_url);
return;
}

BitmapFetcherHandler* bitmap_fetcher_handler =
new BitmapFetcherHandler(this, image_url);
bitmap_fetcher_handler->Start(
browser_context_, referrer, referrer_policy,
net::LOAD_DO_NOT_SEND_COOKIES | net::LOAD_DO_NOT_SAVE_COOKIES,
update_bookmark, page_url);
}

void BookmarkImageServiceAndroid::RetrieveSalientImageFromContext(
content::RenderFrameHost* render_frame_host,
const GURL& page_url,
bool update_bookmark) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
if (IsPageUrlInProgress(page_url))
return; // A request for this URL is already in progress.

const BookmarkNode* bookmark = enhanced_bookmark_model_->bookmark_model()
->GetMostRecentlyAddedUserNodeForURL(page_url);
if (!bookmark)
return;

// Stop the image extraction if there is already an image present.
GURL url;
int height, width;
if (enhanced_bookmark_model_->GetOriginalImage(bookmark, &url, &width,
&height) ||
enhanced_bookmark_model_->GetThumbnailImage(bookmark, &url, &width,
&height)) {
return;
}

if (script_.empty()) {
script_ =
base::UTF8ToUTF16(ResourceBundle::GetSharedInstance()
.GetRawDataResource(IDR_GET_SALIENT_IMAGE_URL_JS)
.as_string());
}

render_frame_host->ExecuteJavaScript(
script_,
base::Bind(
&BookmarkImageServiceAndroid::RetrieveSalientImageFromContextCallback,
base::Unretained(this), page_url, update_bookmark));
}

void BookmarkImageServiceAndroid::FinishSuccessfulPageLoadForTab(
content::WebContents* web_contents, bool update_bookmark) {
content::NavigationEntry* entry =
web_contents->GetController().GetVisibleEntry();

// If the navigation is a simple back or forward, do not extract images, those
// were extracted already.
if (!entry || (entry->GetTransitionType() & ui::PAGE_TRANSITION_FORWARD_BACK))
return;
const GURL& entry_url = entry->GetURL();
const GURL& entry_original_url = entry->GetOriginalRequestURL();
std::vector<GURL> urls;
urls.push_back(entry_url);
if (entry_url != entry_original_url)
urls.push_back(entry_original_url);
for (GURL url : urls) {
if (enhanced_bookmark_model_->bookmark_model()->IsBookmarked(url)) {
RetrieveSalientImageFromContext(web_contents->GetMainFrame(), url,
update_bookmark);
}
}
}

void BookmarkImageServiceAndroid::RetrieveSalientImageFromContextCallback(
const GURL& page_url,
bool update_bookmark,
const base::Value* result) {
if (!result)
return;

std::string json;
if (!result->GetAsString(&json)) {
LOG(WARNING)
<< "Salient image extracting script returned non-string result.";
return;
}

scoped_ptr<base::Value> json_data;
int error_code = 0;
std::string errorMessage;
json_data.reset(base::JSONReader::ReadAndReturnError(
json, base::JSON_PARSE_RFC, &error_code, &errorMessage));
if (error_code || !json_data) {
LOG(WARNING) << "JSON parse error: " << errorMessage.c_str() << json;
return;
}

base::DictionaryValue* dict;
if (!json_data->GetAsDictionary(&dict)) {
LOG(WARNING) << "JSON parse error, not a dict: " << json;
return;
}

std::string referrerPolicy;
std::string image_url;
dict->GetString("referrerPolicy", &referrerPolicy);
dict->GetString("imageUrl", &image_url);

// The policy strings are guaranteed to be in lower-case.
blink::WebReferrerPolicy policy = blink::WebReferrerPolicyDefault;
if (referrerPolicy == "never")
policy = blink::WebReferrerPolicyNever;
if (referrerPolicy == "always")
policy = blink::WebReferrerPolicyAlways;
if (referrerPolicy == "origin")
policy = blink::WebReferrerPolicyOrigin;

in_progress_page_urls_.insert(page_url);

Referrer referrer =
Referrer::SanitizeForRequest(GURL(image_url), Referrer(page_url, policy));
net::URLRequest::ReferrerPolicy referrer_policy =
net::URLRequest::CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE;
if (!referrer.url.is_empty()) {
switch (policy) {
case blink::WebReferrerPolicyDefault:
break;
case blink::WebReferrerPolicyAlways:
case blink::WebReferrerPolicyNever:
case blink::WebReferrerPolicyOrigin:
referrer_policy = net::URLRequest::NEVER_CLEAR_REFERRER;
break;
default:
NOTREACHED();
}
}
RetrieveSalientImage(page_url, GURL(image_url), referrer.url.spec(),
referrer_policy, update_bookmark);
}

void BookmarkImageServiceAndroid::BitmapFetcherHandler::Start(
content::BrowserContext* browser_context,
const std::string& referrer,
net::URLRequest::ReferrerPolicy referrer_policy,
int load_flags,
bool update_bookmark,
const GURL& page_url) {
update_bookmark_ = update_bookmark;
page_url_ = page_url;

bitmap_fetcher_.Start(browser_context->GetRequestContext(), referrer,
referrer_policy, load_flags);
}

void BookmarkImageServiceAndroid::BitmapFetcherHandler::OnFetchComplete(
const GURL url,
const SkBitmap* bitmap) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));

gfx::Image image;
if (bitmap) {
gfx::ImageSkia imageSkia = gfx::ImageSkia::CreateFrom1xBitmap(*bitmap);
imageSkia.MakeThreadSafe();
image = gfx::Image(imageSkia);
}
service_->ProcessNewImage(page_url_, update_bookmark_, image, url);

delete this;
}

} // namespace enhanced_bookmarks
Loading

0 comments on commit 566c432

Please sign in to comment.