Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/android/shortcut_helper.h" | 5 #include "chrome/browser/android/shortcut_helper.h" |
| 6 | 6 |
| 7 #include <jni.h> | 7 #include <jni.h> |
| 8 | 8 |
| 9 #include "base/android/jni_android.h" | 9 #include "base/android/jni_android.h" |
| 10 #include "base/android/jni_string.h" | 10 #include "base/android/jni_string.h" |
| 11 #include "base/basictypes.h" | 11 #include "base/basictypes.h" |
| 12 #include "base/location.h" | 12 #include "base/location.h" |
| 13 #include "base/strings/string16.h" | 13 #include "base/strings/string16.h" |
| 14 #include "base/task/cancelable_task_tracker.h" | 14 #include "base/task/cancelable_task_tracker.h" |
| 15 #include "base/threading/worker_pool.h" | 15 #include "base/threading/worker_pool.h" |
| 16 #include "chrome/browser/android/tab_android.h" | 16 #include "chrome/browser/android/tab_android.h" |
| 17 #include "chrome/browser/favicon/favicon_service.h" | 17 #include "chrome/browser/favicon/favicon_service.h" |
| 18 #include "chrome/browser/favicon/favicon_service_factory.h" | 18 #include "chrome/browser/favicon/favicon_service_factory.h" |
| 19 #include "chrome/common/render_messages.h" | 19 #include "chrome/common/render_messages.h" |
| 20 #include "content/public/browser/user_metrics.h" | 20 #include "content/public/browser/user_metrics.h" |
| 21 #include "content/public/browser/web_contents.h" | 21 #include "content/public/browser/web_contents.h" |
| 22 #include "content/public/browser/web_contents_observer.h" | 22 #include "content/public/browser/web_contents_observer.h" |
| 23 #include "content/public/common/frame_navigate_params.h" | 23 #include "content/public/common/frame_navigate_params.h" |
| 24 #include "content/public/common/manifest.h" | |
| 24 #include "jni/ShortcutHelper_jni.h" | 25 #include "jni/ShortcutHelper_jni.h" |
| 25 #include "ui/gfx/android/java_bitmap.h" | 26 #include "ui/gfx/android/java_bitmap.h" |
| 26 #include "ui/gfx/codec/png_codec.h" | 27 #include "ui/gfx/codec/png_codec.h" |
| 27 #include "ui/gfx/color_analysis.h" | 28 #include "ui/gfx/color_analysis.h" |
| 28 #include "ui/gfx/favicon_size.h" | 29 #include "ui/gfx/favicon_size.h" |
| 29 #include "url/gurl.h" | 30 #include "url/gurl.h" |
| 30 | 31 |
| 31 ShortcutBuilder::ShortcutBuilder(content::WebContents* web_contents, | 32 jlong Initialize(JNIEnv* env, jobject obj, jlong tab_android_ptr) { |
| 32 const base::string16& title, | 33 TabAndroid* tab = reinterpret_cast<TabAndroid*>(tab_android_ptr); |
| 33 int launcher_large_icon_size) | 34 |
| 34 : launcher_large_icon_size_(launcher_large_icon_size), | 35 ShortcutHelper* shortcut_helper = |
| 36 new ShortcutHelper(env, obj, tab->web_contents()); | |
| 37 shortcut_helper->Initialize(); | |
| 38 | |
| 39 return reinterpret_cast<intptr_t>(shortcut_helper); | |
| 40 } | |
| 41 | |
| 42 ShortcutHelper::ShortcutHelper(JNIEnv* env, | |
| 43 jobject obj, | |
| 44 content::WebContents* web_contents) | |
| 45 : WebContentsObserver(web_contents), | |
| 46 java_ref_(env, obj), | |
| 47 url_(web_contents->GetURL()), | |
| 35 shortcut_type_(BOOKMARK) { | 48 shortcut_type_(BOOKMARK) { |
| 36 Observe(web_contents); | 49 } |
| 37 url_ = web_contents->GetURL(); | |
| 38 if (title.length() > 0) | |
| 39 title_ = title; | |
| 40 else | |
| 41 title_ = web_contents->GetTitle(); | |
| 42 | 50 |
| 51 void ShortcutHelper::Initialize() { | |
| 43 // Send a message to the renderer to retrieve information about the page. | 52 // Send a message to the renderer to retrieve information about the page. |
| 44 Send(new ChromeViewMsg_RetrieveWebappInformation(routing_id(), url_)); | 53 Send(new ChromeViewMsg_RetrieveWebappInformation(routing_id(), url_)); |
| 45 } | 54 } |
| 46 | 55 |
| 47 void ShortcutBuilder::OnDidRetrieveWebappInformation( | 56 ShortcutHelper::~ShortcutHelper() { |
| 57 java_ref_.reset(); | |
| 58 } | |
| 59 | |
| 60 void ShortcutHelper::OnDidRetrieveWebappInformation( | |
| 48 bool success, | 61 bool success, |
| 49 bool is_mobile_webapp_capable, | 62 bool is_mobile_webapp_capable, |
| 50 bool is_apple_mobile_webapp_capable, | 63 bool is_apple_mobile_webapp_capable, |
| 51 const GURL& expected_url) { | 64 const GURL& expected_url) { |
| 52 Profile* profile = | 65 // This should silently fail. |
| 53 Profile::FromBrowserContext(web_contents()->GetBrowserContext()); | |
| 54 Observe(NULL); | |
| 55 | |
| 56 if (!success) { | 66 if (!success) { |
| 57 LOG(ERROR) << "Failed to parse webpage."; | 67 LOG(ERROR) << "Failed to parse webpage."; |
| 58 Destroy(); | |
| 59 return; | |
| 60 } else if (expected_url != url_) { | 68 } else if (expected_url != url_) { |
| 61 LOG(ERROR) << "Unexpected URL returned."; | 69 LOG(ERROR) << "Unexpected URL returned."; |
| 62 Destroy(); | |
| 63 return; | |
| 64 } | 70 } |
| 65 | 71 |
| 66 if (is_apple_mobile_webapp_capable && !is_mobile_webapp_capable) { | 72 if (is_apple_mobile_webapp_capable && !is_mobile_webapp_capable) { |
| 67 shortcut_type_ = APP_SHORTCUT_APPLE; | 73 shortcut_type_ = APP_SHORTCUT_APPLE; |
| 68 } else if (is_apple_mobile_webapp_capable || is_mobile_webapp_capable) { | 74 } else if (is_apple_mobile_webapp_capable || is_mobile_webapp_capable) { |
| 69 shortcut_type_ = APP_SHORTCUT; | 75 shortcut_type_ = APP_SHORTCUT; |
| 70 } else { | 76 } else { |
| 71 shortcut_type_ = BOOKMARK; | 77 shortcut_type_ = BOOKMARK; |
| 72 } | 78 } |
| 73 | 79 |
| 80 title_ = web_contents()->GetTitle(); | |
| 81 | |
| 82 JNIEnv* env = base::android::AttachCurrentThread(); | |
| 83 ScopedJavaLocalRef<jobject> j_obj = java_ref_.get(env); | |
| 84 ScopedJavaLocalRef<jstring> j_title = | |
| 85 base::android::ConvertUTF16ToJavaString(env, title_); | |
| 86 | |
| 87 Java_ShortcutHelper_onInitialized(env, j_obj.obj(), j_title.obj()); | |
| 88 } | |
| 89 | |
| 90 void ShortcutHelper::TearDown(JNIEnv*, jobject) { | |
| 91 Destroy(); | |
| 92 } | |
| 93 | |
| 94 void ShortcutHelper::Destroy() { | |
| 95 if (cancelable_task_tracker_.HasTrackedTasks()) { | |
| 96 cancelable_task_tracker_.TryCancelAll(); | |
| 97 } | |
| 98 java_ref_.reset(); | |
| 99 delete this; | |
| 100 } | |
| 101 | |
| 102 void ShortcutHelper::AddShortcut( | |
| 103 JNIEnv* env, jobject, jstring jtitle, jint launcher_large_icon_size) { | |
|
gone
2014/09/11 18:24:37
nit: each variable on its own line
mlamouri (slow - plz ping)
2014/09/11 19:31:02
Done.
| |
| 104 title_ = base::android::ConvertJavaStringToUTF16(env, jtitle); | |
| 105 | |
| 106 Profile* profile = | |
| 107 Profile::FromBrowserContext(web_contents()->GetBrowserContext()); | |
| 108 | |
| 74 // Grab the best, largest icon we can find to represent this bookmark. | 109 // Grab the best, largest icon we can find to represent this bookmark. |
| 75 // TODO(dfalcantara): Try combining with the new BookmarksHandler once its | 110 // TODO(dfalcantara): Try combining with the new BookmarksHandler once its |
| 76 // rewrite is further along. | 111 // rewrite is further along. |
| 77 std::vector<int> icon_types; | 112 std::vector<int> icon_types; |
| 78 icon_types.push_back(favicon_base::FAVICON); | 113 icon_types.push_back(favicon_base::FAVICON); |
| 79 icon_types.push_back(favicon_base::TOUCH_PRECOMPOSED_ICON | | 114 icon_types.push_back(favicon_base::TOUCH_PRECOMPOSED_ICON | |
| 80 favicon_base::TOUCH_ICON); | 115 favicon_base::TOUCH_ICON); |
| 81 FaviconService* favicon_service = FaviconServiceFactory::GetForProfile( | 116 FaviconService* favicon_service = FaviconServiceFactory::GetForProfile( |
| 82 profile, Profile::EXPLICIT_ACCESS); | 117 profile, Profile::EXPLICIT_ACCESS); |
| 83 | 118 |
| 84 // Using favicon if its size is not smaller than platform required size, | 119 // Using favicon if its size is not smaller than platform required size, |
| 85 // otherwise using the largest icon among all avaliable icons. | 120 // otherwise using the largest icon among all avaliable icons. |
| 86 int threshold_to_get_any_largest_icon = launcher_large_icon_size_ - 1; | 121 int threshold_to_get_any_largest_icon = launcher_large_icon_size_ - 1; |
| 87 favicon_service->GetLargestRawFaviconForPageURL(url_, icon_types, | 122 favicon_service->GetLargestRawFaviconForPageURL(url_, icon_types, |
| 88 threshold_to_get_any_largest_icon, | 123 threshold_to_get_any_largest_icon, |
| 89 base::Bind(&ShortcutBuilder::FinishAddingShortcut, | 124 base::Bind(&ShortcutHelper::FinishAddingShortcut, |
| 90 base::Unretained(this)), | 125 base::Unretained(this)), |
| 91 &cancelable_task_tracker_); | 126 &cancelable_task_tracker_); |
| 92 } | 127 } |
| 93 | 128 |
| 94 void ShortcutBuilder::FinishAddingShortcut( | 129 void ShortcutHelper::FinishAddingShortcut( |
| 95 const favicon_base::FaviconRawBitmapResult& bitmap_result) { | 130 const favicon_base::FaviconRawBitmapResult& bitmap_result) { |
| 131 icon_ = bitmap_result; | |
| 132 | |
| 133 // Stop observing so we don't get destroyed while doing the last steps. | |
| 134 Observe(NULL); | |
| 135 | |
| 96 base::WorkerPool::PostTask( | 136 base::WorkerPool::PostTask( |
| 97 FROM_HERE, | 137 FROM_HERE, |
| 98 base::Bind(&ShortcutHelper::AddShortcutInBackground, | 138 base::Bind(&ShortcutHelper::AddShortcutInBackground, |
| 99 url_, | 139 url_, |
| 100 title_, | 140 title_, |
| 101 shortcut_type_, | 141 shortcut_type_, |
| 102 bitmap_result), | 142 icon_), |
| 103 true); | 143 true); |
| 144 | |
| 104 Destroy(); | 145 Destroy(); |
| 105 } | 146 } |
| 106 | 147 |
| 107 bool ShortcutBuilder::OnMessageReceived(const IPC::Message& message) { | 148 bool ShortcutHelper::OnMessageReceived(const IPC::Message& message) { |
| 108 bool handled = true; | 149 bool handled = true; |
| 109 IPC_BEGIN_MESSAGE_MAP(ShortcutBuilder, message) | 150 |
| 151 IPC_BEGIN_MESSAGE_MAP(ShortcutHelper, message) | |
| 110 IPC_MESSAGE_HANDLER(ChromeViewHostMsg_DidRetrieveWebappInformation, | 152 IPC_MESSAGE_HANDLER(ChromeViewHostMsg_DidRetrieveWebappInformation, |
| 111 OnDidRetrieveWebappInformation) | 153 OnDidRetrieveWebappInformation) |
| 112 IPC_MESSAGE_UNHANDLED(handled = false) | 154 IPC_MESSAGE_UNHANDLED(handled = false) |
| 113 IPC_END_MESSAGE_MAP() | 155 IPC_END_MESSAGE_MAP() |
| 156 | |
| 114 return handled; | 157 return handled; |
| 115 } | 158 } |
| 116 | 159 |
| 117 void ShortcutBuilder::WebContentsDestroyed() { | 160 void ShortcutHelper::WebContentsDestroyed() { |
| 118 Destroy(); | 161 Destroy(); |
| 119 } | 162 } |
| 120 | 163 |
| 121 void ShortcutBuilder::Destroy() { | |
| 122 if (cancelable_task_tracker_.HasTrackedTasks()) { | |
| 123 cancelable_task_tracker_.TryCancelAll(); | |
| 124 } | |
| 125 delete this; | |
| 126 } | |
| 127 | |
| 128 void ShortcutHelper::AddShortcut(content::WebContents* web_contents, | |
| 129 const base::string16& title, | |
| 130 int launcher_large_icon_size) { | |
| 131 // The ShortcutBuilder deletes itself when it's done. | |
| 132 new ShortcutBuilder(web_contents, title, launcher_large_icon_size); | |
| 133 } | |
| 134 | |
| 135 bool ShortcutHelper::RegisterShortcutHelper(JNIEnv* env) { | 164 bool ShortcutHelper::RegisterShortcutHelper(JNIEnv* env) { |
| 136 return RegisterNativesImpl(env); | 165 return RegisterNativesImpl(env); |
| 137 } | 166 } |
| 138 | 167 |
| 139 void ShortcutHelper::AddShortcutInBackground( | 168 void ShortcutHelper::AddShortcutInBackground( |
| 140 const GURL& url, | 169 const GURL& url, |
| 141 const base::string16& title, | 170 const base::string16& title, |
| 142 ShortcutBuilder::ShortcutType shortcut_type, | 171 ShortcutType shortcut_type, |
| 143 const favicon_base::FaviconRawBitmapResult& bitmap_result) { | 172 const favicon_base::FaviconRawBitmapResult& bitmap_result) { |
| 144 DCHECK(base::WorkerPool::RunsTasksOnCurrentThread()); | 173 DCHECK(base::WorkerPool::RunsTasksOnCurrentThread()); |
| 145 | 174 |
| 146 // Grab the average color from the bitmap. | 175 // Grab the average color from the bitmap. |
| 147 SkColor color = SK_ColorWHITE; | 176 SkColor color = SK_ColorWHITE; |
| 148 SkBitmap favicon_bitmap; | 177 SkBitmap favicon_bitmap; |
| 149 if (bitmap_result.is_valid()) { | 178 if (bitmap_result.is_valid()) { |
| 150 if (gfx::PNGCodec::Decode(bitmap_result.bitmap_data->front(), | 179 if (gfx::PNGCodec::Decode(bitmap_result.bitmap_data->front(), |
| 151 bitmap_result.bitmap_data->size(), | 180 bitmap_result.bitmap_data->size(), |
| 152 &favicon_bitmap)) | 181 &favicon_bitmap)) |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 168 java_bitmap = gfx::ConvertToJavaBitmap(&favicon_bitmap); | 197 java_bitmap = gfx::ConvertToJavaBitmap(&favicon_bitmap); |
| 169 | 198 |
| 170 Java_ShortcutHelper_addShortcut(env, | 199 Java_ShortcutHelper_addShortcut(env, |
| 171 base::android::GetApplicationContext(), | 200 base::android::GetApplicationContext(), |
| 172 java_url.obj(), | 201 java_url.obj(), |
| 173 java_title.obj(), | 202 java_title.obj(), |
| 174 java_bitmap.obj(), | 203 java_bitmap.obj(), |
| 175 r_value, | 204 r_value, |
| 176 g_value, | 205 g_value, |
| 177 b_value, | 206 b_value, |
| 178 shortcut_type != ShortcutBuilder::BOOKMARK); | 207 shortcut_type != BOOKMARK); |
| 179 | 208 |
| 180 // Record what type of shortcut was added by the user. | 209 // Record what type of shortcut was added by the user. |
| 181 switch (shortcut_type) { | 210 switch (shortcut_type) { |
| 182 case ShortcutBuilder::APP_SHORTCUT: | 211 case APP_SHORTCUT: |
| 183 content::RecordAction( | 212 content::RecordAction( |
| 184 base::UserMetricsAction("webapps.AddShortcut.AppShortcut")); | 213 base::UserMetricsAction("webapps.AddShortcut.AppShortcut")); |
| 185 break; | 214 break; |
| 186 case ShortcutBuilder::APP_SHORTCUT_APPLE: | 215 case APP_SHORTCUT_APPLE: |
| 187 content::RecordAction( | 216 content::RecordAction( |
| 188 base::UserMetricsAction("webapps.AddShortcut.AppShortcutApple")); | 217 base::UserMetricsAction("webapps.AddShortcut.AppShortcutApple")); |
| 189 break; | 218 break; |
| 190 case ShortcutBuilder::BOOKMARK: | 219 case BOOKMARK: |
| 191 content::RecordAction( | 220 content::RecordAction( |
| 192 base::UserMetricsAction("webapps.AddShortcut.Bookmark")); | 221 base::UserMetricsAction("webapps.AddShortcut.Bookmark")); |
| 193 break; | 222 break; |
| 194 default: | 223 default: |
| 195 NOTREACHED(); | 224 NOTREACHED(); |
| 196 } | 225 } |
| 197 } | 226 } |
| 198 | |
| 199 // Adds a shortcut to the current URL to the Android home screen, firing | |
| 200 // background tasks to pull all the data required. | |
| 201 // Note that we don't actually care about the tab here -- we just want | |
| 202 // its otherwise inaccessible WebContents. | |
| 203 static void AddShortcut(JNIEnv* env, | |
| 204 jclass clazz, | |
| 205 jlong tab_android_ptr, | |
| 206 jstring title, | |
| 207 jint launcher_large_icon_size) { | |
| 208 TabAndroid* tab = reinterpret_cast<TabAndroid*>(tab_android_ptr); | |
| 209 ShortcutHelper::AddShortcut( | |
| 210 tab->web_contents(), | |
| 211 base::android::ConvertJavaStringToUTF16(env, title), | |
| 212 launcher_large_icon_size); | |
| 213 } | |
| OLD | NEW |