Home | History | Annotate | Download | only in android
      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/most_visited_sites.h"
      6 
      7 #include "base/android/jni_android.h"
      8 #include "base/android/jni_array.h"
      9 #include "base/android/jni_string.h"
     10 #include "base/android/scoped_java_ref.h"
     11 #include "chrome/browser/chrome_notification_types.h"
     12 #include "chrome/browser/history/history_types.h"
     13 #include "chrome/browser/history/top_sites.h"
     14 #include "chrome/browser/profiles/profile.h"
     15 #include "chrome/browser/profiles/profile_android.h"
     16 #include "content/public/browser/browser_thread.h"
     17 #include "content/public/browser/notification_source.h"
     18 #include "jni/MostVisitedSites_jni.h"
     19 #include "third_party/skia/include/core/SkBitmap.h"
     20 #include "ui/gfx/android/java_bitmap.h"
     21 #include "ui/gfx/codec/jpeg_codec.h"
     22 
     23 using base::android::AttachCurrentThread;
     24 using base::android::ConvertUTF8ToJavaString;
     25 using base::android::ConvertJavaStringToUTF8;
     26 using base::android::ScopedJavaGlobalRef;
     27 using base::android::ToJavaArrayOfStrings;
     28 using base::android::CheckException;
     29 using content::BrowserThread;
     30 using history::TopSites;
     31 
     32 namespace {
     33 
     34 void ExtractMostVisitedTitlesAndURLs(
     35     const history::MostVisitedURLList& visited_list,
     36     std::vector<base::string16>* titles,
     37     std::vector<std::string>* urls,
     38     int num_sites) {
     39   size_t max = static_cast<size_t>(num_sites);
     40   for (size_t i = 0; i < visited_list.size() && i < max; ++i) {
     41     const history::MostVisitedURL& visited = visited_list[i];
     42 
     43     if (visited.url.is_empty())
     44       break;  // This is the signal that there are no more real visited sites.
     45 
     46     titles->push_back(visited.title);
     47     urls->push_back(visited.url.spec());
     48   }
     49 }
     50 
     51 void OnMostVisitedURLsAvailable(
     52     ScopedJavaGlobalRef<jobject>* j_observer,
     53     int num_sites,
     54     const history::MostVisitedURLList& visited_list) {
     55   std::vector<base::string16> titles;
     56   std::vector<std::string> urls;
     57   ExtractMostVisitedTitlesAndURLs(visited_list, &titles, &urls, num_sites);
     58 
     59   JNIEnv* env = AttachCurrentThread();
     60   Java_MostVisitedURLsObserver_onMostVisitedURLsAvailable(
     61       env,
     62       j_observer->obj(),
     63       ToJavaArrayOfStrings(env, titles).obj(),
     64       ToJavaArrayOfStrings(env, urls).obj());
     65 }
     66 
     67 SkBitmap ExtractThumbnail(const base::RefCountedMemory& image_data) {
     68   scoped_ptr<SkBitmap> image(gfx::JPEGCodec::Decode(
     69       image_data.front(),
     70       image_data.size()));
     71   return image.get() ? *image : SkBitmap();
     72 }
     73 
     74 void OnObtainedThumbnail(
     75     ScopedJavaGlobalRef<jobject>* bitmap,
     76     ScopedJavaGlobalRef<jobject>* j_callback) {
     77   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
     78   JNIEnv* env = AttachCurrentThread();
     79   Java_ThumbnailCallback_onMostVisitedURLsThumbnailAvailable(
     80       env, j_callback->obj(), bitmap->obj());
     81 }
     82 
     83 void GetUrlThumbnailTask(
     84     std::string url_string,
     85     scoped_refptr<TopSites> top_sites,
     86     ScopedJavaGlobalRef<jobject>* j_callback) {
     87   JNIEnv* env = AttachCurrentThread();
     88 
     89   ScopedJavaGlobalRef<jobject>* j_bitmap_ref =
     90       new ScopedJavaGlobalRef<jobject>();
     91 
     92   GURL gurl(url_string);
     93 
     94   scoped_refptr<base::RefCountedMemory> data;
     95   if (top_sites->GetPageThumbnail(gurl, false, &data)) {
     96     SkBitmap thumbnail_bitmap = ExtractThumbnail(*data.get());
     97     if (!thumbnail_bitmap.empty()) {
     98       j_bitmap_ref->Reset(
     99           env,
    100           gfx::ConvertToJavaBitmap(&thumbnail_bitmap).obj());
    101     }
    102   }
    103 
    104   // Since j_callback is owned by this callback, when the callback falls out of
    105   // scope it will be deleted. We need to pass ownership to the next callback.
    106   ScopedJavaGlobalRef<jobject>* j_callback_pass =
    107       new ScopedJavaGlobalRef<jobject>(*j_callback);
    108   BrowserThread::PostTask(
    109       BrowserThread::UI, FROM_HERE,
    110       base::Bind(
    111           &OnObtainedThumbnail,
    112           base::Owned(j_bitmap_ref), base::Owned(j_callback_pass)));
    113 }
    114 
    115 }  // namespace
    116 
    117 MostVisitedSites::MostVisitedSites(Profile* profile)
    118     : profile_(profile), num_sites_(0) {
    119 }
    120 
    121 MostVisitedSites::~MostVisitedSites() {
    122 }
    123 
    124 void MostVisitedSites::Destroy(JNIEnv* env, jobject obj) {
    125   delete this;
    126 }
    127 
    128 void MostVisitedSites::SetMostVisitedURLsObserver(JNIEnv* env,
    129                                                   jobject obj,
    130                                                   jobject j_observer,
    131                                                   jint num_sites) {
    132   observer_.Reset(env, j_observer);
    133   num_sites_ = num_sites;
    134 
    135   QueryMostVisitedURLs();
    136 
    137   history::TopSites* top_sites = profile_->GetTopSites();
    138   if (top_sites) {
    139     // TopSites updates itself after a delay. To ensure up-to-date results,
    140     // force an update now.
    141     top_sites->SyncWithHistory();
    142 
    143     // Register for notification when TopSites changes so that we can update
    144     // ourself.
    145     registrar_.Add(this, chrome::NOTIFICATION_TOP_SITES_CHANGED,
    146                    content::Source<history::TopSites>(top_sites));
    147   }
    148 }
    149 
    150 // May be called from any thread
    151 void MostVisitedSites::GetURLThumbnail(JNIEnv* env,
    152                                        jobject obj,
    153                                        jstring url,
    154                                        jobject j_callback_obj) {
    155   ScopedJavaGlobalRef<jobject>* j_callback =
    156       new ScopedJavaGlobalRef<jobject>();
    157   j_callback->Reset(env, j_callback_obj);
    158 
    159   std::string url_string = ConvertJavaStringToUTF8(env, url);
    160   scoped_refptr<TopSites> top_sites(profile_->GetTopSites());
    161   BrowserThread::PostTask(
    162       BrowserThread::DB, FROM_HERE, base::Bind(
    163           &GetUrlThumbnailTask,
    164           url_string,
    165           top_sites, base::Owned(j_callback)));
    166 }
    167 
    168 void MostVisitedSites::BlacklistUrl(JNIEnv* env,
    169                                     jobject obj,
    170                                     jstring j_url) {
    171   TopSites* top_sites = profile_->GetTopSites();
    172   if (!top_sites)
    173     return;
    174 
    175   std::string url_string = ConvertJavaStringToUTF8(env, j_url);
    176   top_sites->AddBlacklistedURL(GURL(url_string));
    177 }
    178 
    179 void MostVisitedSites::Observe(int type,
    180                                const content::NotificationSource& source,
    181                                const content::NotificationDetails& details) {
    182   DCHECK_EQ(type, chrome::NOTIFICATION_TOP_SITES_CHANGED);
    183 
    184   // Most visited urls changed, query again.
    185   QueryMostVisitedURLs();
    186 }
    187 
    188 // static
    189 bool MostVisitedSites::Register(JNIEnv* env) {
    190   return RegisterNativesImpl(env);
    191 }
    192 
    193 void MostVisitedSites::QueryMostVisitedURLs() {
    194   TopSites* top_sites = profile_->GetTopSites();
    195   if (!top_sites)
    196     return;
    197 
    198   top_sites->GetMostVisitedURLs(
    199       base::Bind(
    200           &OnMostVisitedURLsAvailable,
    201           base::Owned(new ScopedJavaGlobalRef<jobject>(observer_)),
    202           num_sites_),
    203       false);
    204 }
    205 
    206 static jlong Init(JNIEnv* env, jobject obj, jobject jprofile) {
    207   MostVisitedSites* most_visited_sites =
    208       new MostVisitedSites(ProfileAndroid::FromProfileAndroid(jprofile));
    209   return reinterpret_cast<intptr_t>(most_visited_sites);
    210 }
    211