shortcut_helper.cc revision 424c4d7b64af9d0d8fd9624f381f469654d5e3d2
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/shortcut_helper.h" 6 7#include <jni.h> 8 9#include "base/android/jni_android.h" 10#include "base/android/jni_string.h" 11#include "base/basictypes.h" 12#include "base/location.h" 13#include "base/strings/string16.h" 14#include "base/threading/worker_pool.h" 15#include "chrome/browser/android/tab_android.h" 16#include "chrome/browser/favicon/favicon_service.h" 17#include "chrome/browser/favicon/favicon_service_factory.h" 18#include "chrome/common/cancelable_task_tracker.h" 19#include "chrome/common/render_messages.h" 20#include "content/public/browser/web_contents.h" 21#include "content/public/browser/web_contents_observer.h" 22#include "content/public/common/frame_navigate_params.h" 23#include "jni/ShortcutHelper_jni.h" 24#include "ui/gfx/android/java_bitmap.h" 25#include "ui/gfx/codec/png_codec.h" 26#include "ui/gfx/color_analysis.h" 27#include "url/gurl.h" 28 29ShortcutBuilder::ShortcutBuilder(content::WebContents* web_contents) 30 : is_webapp_capable_(false) { 31 Observe(web_contents); 32 url_ = web_contents->GetURL(); 33 title_ = web_contents->GetTitle(); 34 35 // Send a message to the renderer to retrieve information about the page. 36 Send(new ChromeViewMsg_RetrieveWebappInformation(routing_id(), url_)); 37} 38 39void ShortcutBuilder::OnDidRetrieveWebappInformation(bool success, 40 bool is_webapp_capable, 41 const GURL& expected_url) { 42 Profile* profile = 43 Profile::FromBrowserContext(web_contents()->GetBrowserContext()); 44 Observe(NULL); 45 46 if (!success) { 47 LOG(ERROR) << "Failed to parse webpage."; 48 Destroy(); 49 return; 50 } else if (expected_url != url_) { 51 LOG(ERROR) << "Unexpected URL returned."; 52 Destroy(); 53 return; 54 } 55 is_webapp_capable_ = is_webapp_capable; 56 57 // Grab the best, largest icon we can find to represent this bookmark. 58 // TODO(dfalcantara): Try combining with the new BookmarksHandler once its 59 // rewrite is further along. 60 FaviconService::FaviconForURLParams favicon_params( 61 profile, 62 url_, 63 chrome::TOUCH_PRECOMPOSED_ICON | chrome::TOUCH_ICON | chrome::FAVICON, 64 0); 65 66 FaviconService* favicon_service = FaviconServiceFactory::GetForProfile( 67 profile, Profile::EXPLICIT_ACCESS); 68 69 favicon_service->GetRawFaviconForURL( 70 favicon_params, 71 ui::SCALE_FACTOR_100P, 72 base::Bind(&ShortcutBuilder::FinishAddingShortcut, 73 base::Unretained(this)), 74 &cancelable_task_tracker_); 75} 76 77void ShortcutBuilder::FinishAddingShortcut( 78 const chrome::FaviconBitmapResult& bitmap_result) { 79 base::WorkerPool::PostTask( 80 FROM_HERE, 81 base::Bind(&ShortcutHelper::AddShortcutInBackground, 82 url_, 83 title_, 84 is_webapp_capable_, 85 bitmap_result), 86 true); 87 Destroy(); 88} 89 90bool ShortcutBuilder::OnMessageReceived(const IPC::Message& message) { 91 bool handled = true; 92 IPC_BEGIN_MESSAGE_MAP(ShortcutBuilder, message) 93 IPC_MESSAGE_HANDLER(ChromeViewHostMsg_DidRetrieveWebappInformation, 94 OnDidRetrieveWebappInformation) 95 IPC_MESSAGE_UNHANDLED(handled = false) 96 IPC_END_MESSAGE_MAP() 97 return handled; 98} 99 100void ShortcutBuilder::WebContentsDestroyed(content::WebContents* web_contents) { 101 Destroy(); 102} 103 104void ShortcutBuilder::Destroy() { 105 if (cancelable_task_tracker_.HasTrackedTasks()) { 106 cancelable_task_tracker_.TryCancelAll(); 107 } 108 delete this; 109} 110 111void ShortcutHelper::AddShortcut(content::WebContents* web_contents) { 112 // The ShortcutBuilder deletes itself when it's done. 113 new ShortcutBuilder(web_contents); 114} 115 116bool ShortcutHelper::RegisterShortcutHelper(JNIEnv* env) { 117 return RegisterNativesImpl(env); 118} 119 120void ShortcutHelper::AddShortcutInBackground( 121 const GURL& url, 122 const string16& title, 123 bool is_webapp_capable, 124 const chrome::FaviconBitmapResult& bitmap_result) { 125 DCHECK(base::WorkerPool::RunsTasksOnCurrentThread()); 126 127 // Grab the average color from the bitmap. 128 SkColor color = SK_ColorWHITE; 129 SkBitmap favicon_bitmap; 130 if (bitmap_result.is_valid()) { 131 color_utils::GridSampler sampler; 132 color = color_utils::CalculateKMeanColorOfPNG(bitmap_result.bitmap_data, 133 100, 134 665, 135 &sampler); 136 gfx::PNGCodec::Decode(bitmap_result.bitmap_data->front(), 137 bitmap_result.bitmap_data->size(), 138 &favicon_bitmap); 139 } 140 141 int r_value = SkColorGetR(color); 142 int g_value = SkColorGetG(color); 143 int b_value = SkColorGetB(color); 144 145 // Send the data to the Java side to create the shortcut. 146 JNIEnv* env = base::android::AttachCurrentThread(); 147 ScopedJavaLocalRef<jstring> java_url = 148 base::android::ConvertUTF8ToJavaString(env, url.spec()); 149 ScopedJavaLocalRef<jstring> java_title = 150 base::android::ConvertUTF16ToJavaString(env, title); 151 ScopedJavaLocalRef<jobject> java_bitmap; 152 if (favicon_bitmap.getSize()) 153 java_bitmap = gfx::ConvertToJavaBitmap(&favicon_bitmap); 154 155 Java_ShortcutHelper_addShortcut(env, 156 base::android::GetApplicationContext(), 157 java_url.obj(), 158 java_title.obj(), 159 java_bitmap.obj(), 160 r_value, 161 g_value, 162 b_value, 163 is_webapp_capable); 164} 165 166// Adds a shortcut to the current URL to the Android home screen, firing 167// background tasks to pull all the data required. 168// Note that we don't actually care about the tab here -- we just want 169// its otherwise inaccessible WebContents. 170static void AddShortcut(JNIEnv* env, jclass clazz, jint tab_android_ptr) { 171 TabAndroid* tab = reinterpret_cast<TabAndroid*>(tab_android_ptr); 172 ShortcutHelper::AddShortcut(tab->web_contents()); 173} 174