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