13551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved.
23551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
33551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)// found in the LICENSE file.
43551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
53551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "chrome/browser/android/shortcut_helper.h"
63551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
73551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include <jni.h>
81320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include <limits>
93551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
103551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "base/android/jni_android.h"
113551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "base/android/jni_string.h"
123551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "base/basictypes.h"
133551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "base/location.h"
143551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "base/strings/string16.h"
151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/strings/utf_string_conversions.h"
165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/task/cancelable_task_tracker.h"
173551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "base/threading/worker_pool.h"
183551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "chrome/browser/android/tab_android.h"
193551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "chrome/browser/favicon/favicon_service.h"
203551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "chrome/browser/favicon/favicon_service_factory.h"
211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "chrome/common/chrome_constants.h"
223551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "chrome/common/render_messages.h"
231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "chrome/common/web_application_info.h"
244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "content/public/browser/user_metrics.h"
253551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "content/public/browser/web_contents.h"
263551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "content/public/browser/web_contents_observer.h"
273551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "content/public/common/frame_navigate_params.h"
281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "content/public/common/manifest.h"
293551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "jni/ShortcutHelper_jni.h"
301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "net/base/mime_util.h"
313551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "ui/gfx/android/java_bitmap.h"
323551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "ui/gfx/codec/png_codec.h"
333551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "ui/gfx/color_analysis.h"
341e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include "ui/gfx/favicon_size.h"
351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "ui/gfx/screen.h"
363551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "url/gurl.h"
373551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciusing content::Manifest;
391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// Android's preferred icon size in DP is 48, as defined in
411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// http://developer.android.com/design/style/iconography.html
421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciconst int ShortcutHelper::kPreferredIconSizeInDp = 48;
431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccijlong Initialize(JNIEnv* env, jobject obj, jlong tab_android_ptr) {
451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  TabAndroid* tab = reinterpret_cast<TabAndroid*>(tab_android_ptr);
461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  ShortcutHelper* shortcut_helper =
481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      new ShortcutHelper(env, obj, tab->web_contents());
491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  shortcut_helper->Initialize();
501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return reinterpret_cast<intptr_t>(shortcut_helper);
521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciShortcutHelper::ShortcutHelper(JNIEnv* env,
551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                               jobject obj,
561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                               content::WebContents* web_contents)
571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    : WebContentsObserver(web_contents),
581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      java_ref_(env, obj),
591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      url_(web_contents->GetURL()),
601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      display_(content::Manifest::DISPLAY_MODE_BROWSER),
611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      orientation_(blink::WebScreenOrientationLockDefault),
621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      add_shortcut_requested_(false),
631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      manifest_icon_status_(MANIFEST_ICON_STATUS_NONE),
641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      preferred_icon_size_in_px_(kPreferredIconSizeInDp *
651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          gfx::Screen::GetScreenFor(web_contents->GetNativeView())->
661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci              GetPrimaryDisplay().device_scale_factor()),
671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      weak_ptr_factory_(this) {
681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
693551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid ShortcutHelper::Initialize() {
713551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // Send a message to the renderer to retrieve information about the page.
721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  Send(new ChromeViewMsg_GetWebApplicationInfo(routing_id()));
733551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
743551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciShortcutHelper::~ShortcutHelper() {
761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
77424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid ShortcutHelper::OnDidGetWebApplicationInfo(
791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const WebApplicationInfo& received_web_app_info) {
801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Sanitize received_web_app_info.
811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  WebApplicationInfo web_app_info = received_web_app_info;
821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  web_app_info.title =
831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      web_app_info.title.substr(0, chrome::kMaxMetaTagAttributeLength);
841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  web_app_info.description =
851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      web_app_info.description.substr(0, chrome::kMaxMetaTagAttributeLength);
861320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  title_ = web_app_info.title.empty() ? web_contents()->GetTitle()
881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                      : web_app_info.title;
891320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
901320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (web_app_info.mobile_capable == WebApplicationInfo::MOBILE_CAPABLE ||
911320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      web_app_info.mobile_capable == WebApplicationInfo::MOBILE_CAPABLE_APPLE) {
921320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    display_ = content::Manifest::DISPLAY_MODE_STANDALONE;
931320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
941320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
951320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Record what type of shortcut was added by the user.
961320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  switch (web_app_info.mobile_capable) {
971320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    case WebApplicationInfo::MOBILE_CAPABLE:
981320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      content::RecordAction(
991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          base::UserMetricsAction("webapps.AddShortcut.AppShortcut"));
1001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      break;
1011320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    case WebApplicationInfo::MOBILE_CAPABLE_APPLE:
1021320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      content::RecordAction(
1031320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          base::UserMetricsAction("webapps.AddShortcut.AppShortcutApple"));
1041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      break;
1051320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    case WebApplicationInfo::MOBILE_CAPABLE_UNSPECIFIED:
1061320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      content::RecordAction(
1071320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          base::UserMetricsAction("webapps.AddShortcut.Bookmark"));
1081320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      break;
1091320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
1101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  web_contents()->GetManifest(base::Bind(&ShortcutHelper::OnDidGetManifest,
1121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                         weak_ptr_factory_.GetWeakPtr()));
1131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
1141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccibool ShortcutHelper::IconSizesContainsPreferredSize(
1161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const std::vector<gfx::Size>& sizes) const {
1171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  for (size_t i = 0; i < sizes.size(); ++i) {
1181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if (sizes[i].height() != sizes[i].width())
1191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      continue;
1201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if (sizes[i].width() == preferred_icon_size_in_px_)
1211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      return true;
1221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
1231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return false;
1251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
1261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccibool ShortcutHelper::IconSizesContainsAny(
1281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const std::vector<gfx::Size>& sizes) const {
1291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  for (size_t i = 0; i < sizes.size(); ++i) {
1301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if (sizes[i].IsEmpty())
1311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      return true;
1321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
1331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return false;
1351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
1361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciGURL ShortcutHelper::FindBestMatchingIcon(
1381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const std::vector<Manifest::Icon>& icons, float density) const {
1391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  GURL url;
1401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  int best_delta = std::numeric_limits<int>::min();
1411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  for (size_t i = 0; i < icons.size(); ++i) {
1431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if (icons[i].density != density)
1441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      continue;
1451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const std::vector<gfx::Size>& sizes = icons[i].sizes;
1471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    for (size_t j = 0; j < sizes.size(); ++j) {
1481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      if (sizes[j].height() != sizes[j].width())
1491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        continue;
1501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      int delta = sizes[j].width() - preferred_icon_size_in_px_;
1511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      if (delta == 0)
1521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        return icons[i].src;
1531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      if (best_delta > 0 && delta < 0)
1541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        continue;
1551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      if ((best_delta > 0 && delta < best_delta) ||
1561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          (best_delta < 0 && delta > best_delta)) {
1571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        url = icons[i].src;
1581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        best_delta = delta;
1591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      }
1601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    }
1611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
1621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return url;
1641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
1651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// static
1671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccistd::vector<Manifest::Icon> ShortcutHelper::FilterIconsByType(
1681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const std::vector<Manifest::Icon>& icons) {
1691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  std::vector<Manifest::Icon> result;
1701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  for (size_t i = 0; i < icons.size(); ++i) {
1721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if (icons[i].type.is_null() ||
1731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        net::IsSupportedImageMimeType(
1741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci            base::UTF16ToUTF8(icons[i].type.string()))) {
1751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      result.push_back(icons[i]);
1761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    }
1771320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
1781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return result;
1801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
1811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciGURL ShortcutHelper::FindBestMatchingIcon(
1831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const std::vector<Manifest::Icon>& unfiltered_icons) const {
1841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  const float device_scale_factor =
1851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      gfx::Screen::GetScreenFor(web_contents()->GetNativeView())->
1861320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          GetPrimaryDisplay().device_scale_factor();
1871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  GURL url;
1891320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  std::vector<Manifest::Icon> icons = FilterIconsByType(unfiltered_icons);
1901320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1911320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // The first pass is to find the ideal icon. That icon is of the right size
1921320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // with the default density or the device's density.
1931320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  for (size_t i = 0; i < icons.size(); ++i) {
1941320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if (icons[i].density == device_scale_factor &&
1951320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        IconSizesContainsPreferredSize(icons[i].sizes)) {
1961320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      return icons[i].src;
1971320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    }
1981320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // If there is an icon with the right size but not the right density, keep
2001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // it on the side and only use it if nothing better is found.
2011320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if (icons[i].density == Manifest::Icon::kDefaultDensity &&
2021320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        IconSizesContainsPreferredSize(icons[i].sizes)) {
2031320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      url = icons[i].src;
2041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    }
2051320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
2061320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2071320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // The second pass is to find an icon with 'any'. The current device scale
2081320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // factor is preferred. Otherwise, the default scale factor is used.
2091320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  for (size_t i = 0; i < icons.size(); ++i) {
2101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if (icons[i].density == device_scale_factor &&
2111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        IconSizesContainsAny(icons[i].sizes)) {
2121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      return icons[i].src;
2131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    }
2141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // If there is an icon with 'any' but not the right density, keep it on the
2161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // side and only use it if nothing better is found.
2171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if (icons[i].density == Manifest::Icon::kDefaultDensity &&
2181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        IconSizesContainsAny(icons[i].sizes)) {
2191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      url = icons[i].src;
2201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    }
2211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
2221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // The last pass will try to find the best suitable icon for the device's
2241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // scale factor. If none, another pass will be run using kDefaultDensity.
2251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (!url.is_valid())
2261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    url = FindBestMatchingIcon(icons, device_scale_factor);
2271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (!url.is_valid())
2281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    url = FindBestMatchingIcon(icons, Manifest::Icon::kDefaultDensity);
2291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return url;
2311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
2321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid ShortcutHelper::OnDidGetManifest(const content::Manifest& manifest) {
2341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Set the title based on the manifest value, if any.
2351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (!manifest.short_name.is_null())
2361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    title_ = manifest.short_name.string();
2371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  else if (!manifest.name.is_null())
2381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    title_ = manifest.name.string();
2391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Set the url based on the manifest value, if any.
2411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (manifest.start_url.is_valid())
2421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    url_ = manifest.start_url;
2431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Set the display based on the manifest value, if any.
2451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (manifest.display != content::Manifest::DISPLAY_MODE_UNSPECIFIED)
2461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    display_ = manifest.display;
2471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // 'fullscreen' and 'minimal-ui' are not yet supported, fallback to the right
2491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // mode in those cases.
2501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (manifest.display == content::Manifest::DISPLAY_MODE_FULLSCREEN)
2511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    display_ = content::Manifest::DISPLAY_MODE_STANDALONE;
2521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (manifest.display == content::Manifest::DISPLAY_MODE_MINIMAL_UI)
2531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    display_ = content::Manifest::DISPLAY_MODE_BROWSER;
2541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Set the orientation based on the manifest value, if any.
2561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (manifest.orientation != blink::WebScreenOrientationLockDefault) {
2571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // Ignore the orientation if the display mode is different from
2581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // 'standalone'.
2591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // TODO(mlamouri): send a message to the developer console about this.
2601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if (display_ == content::Manifest::DISPLAY_MODE_STANDALONE)
2611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      orientation_ = manifest.orientation;
2621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
2631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  GURL icon_src = FindBestMatchingIcon(manifest.icons);
2651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (icon_src.is_valid()) {
2661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    web_contents()->DownloadImage(icon_src,
2671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                  false,
2681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                  preferred_icon_size_in_px_,
2691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                  base::Bind(&ShortcutHelper::OnDidDownloadIcon,
2701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                             weak_ptr_factory_.GetWeakPtr()));
2711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    manifest_icon_status_ = MANIFEST_ICON_STATUS_FETCHING;
2721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
2731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // The ShortcutHelper is now able to notify its Java counterpart that it is
2751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // initialized. OnInitialized method is not conceptually part of getting the
2761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // manifest data but it happens that the initialization is finalized when
2771320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // these data are available.
2781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  JNIEnv* env = base::android::AttachCurrentThread();
2791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  ScopedJavaLocalRef<jobject> j_obj = java_ref_.get(env);
2801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  ScopedJavaLocalRef<jstring> j_title =
2811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      base::android::ConvertUTF16ToJavaString(env, title_);
2821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  Java_ShortcutHelper_onInitialized(env, j_obj.obj(), j_title.obj());
2841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
2851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2861320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid ShortcutHelper::OnDidDownloadIcon(int id,
2871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                       int http_status_code,
2881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                       const GURL& url,
2891320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                       const std::vector<SkBitmap>& bitmaps,
2901320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                       const std::vector<gfx::Size>& sizes) {
2911320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // If getting the candidate manifest icon failed, the ShortcutHelper should
2921320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // fallback to the favicon.
2931320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // If the user already requested to add the shortcut, it will do so but use
2941320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // the favicon instead.
2951320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Otherwise, it sets the state as if there was no manifest icon pending.
2961320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (bitmaps.empty()) {
2971320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if (add_shortcut_requested_)
2981320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      AddShortcutUsingFavicon();
2991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    else
3001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      manifest_icon_status_ = MANIFEST_ICON_STATUS_NONE;
3013551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return;
3023551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
3034e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
3041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // There might be multiple bitmaps returned. The one to pick is bigger or
3051320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // equal to the preferred size. |bitmaps| is ordered from bigger to smaller.
3061320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  int preferred_bitmap_index = 0;
3071320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  for (size_t i = 0; i < bitmaps.size(); ++i) {
3081320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if (bitmaps[i].height() < preferred_icon_size_in_px_)
3091320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      break;
3101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    preferred_bitmap_index = i;
3114e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
3123551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
3131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  manifest_icon_ = bitmaps[preferred_bitmap_index];
3141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  manifest_icon_status_ = MANIFEST_ICON_STATUS_DONE;
3151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
3161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (add_shortcut_requested_)
3171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    AddShortcutUsingManifestIcon();
3181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
3191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
3201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid ShortcutHelper::TearDown(JNIEnv*, jobject) {
3211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  Destroy();
3221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
3231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
3241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid ShortcutHelper::Destroy() {
3251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  delete this;
3261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
3271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
3281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid ShortcutHelper::AddShortcut(
3291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    JNIEnv* env,
3301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    jobject obj,
3311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    jstring jtitle,
3321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    jint launcher_large_icon_size) {
3331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  add_shortcut_requested_ = true;
3341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
3351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  base::string16 title = base::android::ConvertJavaStringToUTF16(env, jtitle);
3361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (!title.empty())
3371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    title_ = title;
3381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
3391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  switch (manifest_icon_status_) {
3401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    case MANIFEST_ICON_STATUS_NONE:
3411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      AddShortcutUsingFavicon();
3421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      break;
3431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    case MANIFEST_ICON_STATUS_FETCHING:
3441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      // ::OnDidDownloadIcon() will call AddShortcutUsingManifestIcon().
3451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      break;
3461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    case MANIFEST_ICON_STATUS_DONE:
3471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      AddShortcutUsingManifestIcon();
3481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      break;
3491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
3501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
3511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
3521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid ShortcutHelper::AddShortcutUsingManifestIcon() {
3531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Stop observing so we don't get destroyed while doing the last steps.
3541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  Observe(NULL);
3551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
3561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  base::WorkerPool::PostTask(
3571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      FROM_HERE,
3581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      base::Bind(&ShortcutHelper::AddShortcutInBackgroundWithSkBitmap,
3591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                 url_,
3601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                 title_,
3611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                 display_,
3621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                 manifest_icon_,
3631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                 orientation_),
3641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      true);
3651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
3661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  Destroy();
3671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
3681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
3691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid ShortcutHelper::AddShortcutUsingFavicon() {
3701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  Profile* profile =
3711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      Profile::FromBrowserContext(web_contents()->GetBrowserContext());
3721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
3733551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // Grab the best, largest icon we can find to represent this bookmark.
3743551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // TODO(dfalcantara): Try combining with the new BookmarksHandler once its
3753551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  //                    rewrite is further along.
3761e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  std::vector<int> icon_types;
3770529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  icon_types.push_back(favicon_base::FAVICON);
3780529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  icon_types.push_back(favicon_base::TOUCH_PRECOMPOSED_ICON |
3790529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                       favicon_base::TOUCH_ICON);
3803551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  FaviconService* favicon_service = FaviconServiceFactory::GetForProfile(
381424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      profile, Profile::EXPLICIT_ACCESS);
3823551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
3831e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // Using favicon if its size is not smaller than platform required size,
3841e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // otherwise using the largest icon among all avaliable icons.
3851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  int threshold_to_get_any_largest_icon = preferred_icon_size_in_px_ - 1;
386116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  favicon_service->GetLargestRawFaviconForPageURL(url_, icon_types,
3871e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      threshold_to_get_any_largest_icon,
3881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      base::Bind(&ShortcutHelper::OnDidGetFavicon,
389424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)                 base::Unretained(this)),
3903551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      &cancelable_task_tracker_);
3913551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
3923551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
3931320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid ShortcutHelper::OnDidGetFavicon(
394f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    const favicon_base::FaviconRawBitmapResult& bitmap_result) {
3951320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Stop observing so we don't get destroyed while doing the last steps.
3961320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  Observe(NULL);
3971320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
398424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  base::WorkerPool::PostTask(
399424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      FROM_HERE,
4001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      base::Bind(&ShortcutHelper::AddShortcutInBackgroundWithRawBitmap,
401424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)                 url_,
402424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)                 title_,
4031320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                 display_,
4041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                 bitmap_result,
4051320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                 orientation_),
406424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      true);
4071320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
408424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  Destroy();
4093551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
4103551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
4111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccibool ShortcutHelper::OnMessageReceived(const IPC::Message& message) {
4123551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  bool handled = true;
4131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
4141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  IPC_BEGIN_MESSAGE_MAP(ShortcutHelper, message)
4151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    IPC_MESSAGE_HANDLER(ChromeViewHostMsg_DidGetWebApplicationInfo,
4161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                        OnDidGetWebApplicationInfo)
4173551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    IPC_MESSAGE_UNHANDLED(handled = false)
4183551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  IPC_END_MESSAGE_MAP()
4191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
4203551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  return handled;
4213551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
4223551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
4231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid ShortcutHelper::WebContentsDestroyed() {
424424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  Destroy();
425424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)}
426424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
4273551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)bool ShortcutHelper::RegisterShortcutHelper(JNIEnv* env) {
4283551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  return RegisterNativesImpl(env);
4293551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
4303551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
4311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid ShortcutHelper::AddShortcutInBackgroundWithRawBitmap(
4323551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    const GURL& url,
433a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    const base::string16& title,
4341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    content::Manifest::DisplayMode display,
4351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const favicon_base::FaviconRawBitmapResult& bitmap_result,
4361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    blink::WebScreenOrientationLockType orientation) {
4373551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  DCHECK(base::WorkerPool::RunsTasksOnCurrentThread());
4383551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
4391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  SkBitmap icon_bitmap;
4403551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (bitmap_result.is_valid()) {
4411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    gfx::PNGCodec::Decode(bitmap_result.bitmap_data->front(),
4421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                          bitmap_result.bitmap_data->size(),
4431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                          &icon_bitmap);
4443551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
4453551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
4461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  AddShortcutInBackgroundWithSkBitmap(
4471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      url, title, display, icon_bitmap, orientation);
4481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
4491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
4501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid ShortcutHelper::AddShortcutInBackgroundWithSkBitmap(
4511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const GURL& url,
4521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const base::string16& title,
4531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    content::Manifest::DisplayMode display,
4541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const SkBitmap& icon_bitmap,
4551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    blink::WebScreenOrientationLockType orientation) {
4561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DCHECK(base::WorkerPool::RunsTasksOnCurrentThread());
4571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
4581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  SkColor color = color_utils::CalculateKMeanColorOfBitmap(icon_bitmap);
4593551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  int r_value = SkColorGetR(color);
4603551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  int g_value = SkColorGetG(color);
4613551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  int b_value = SkColorGetB(color);
4623551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
4633551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // Send the data to the Java side to create the shortcut.
4643551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  JNIEnv* env = base::android::AttachCurrentThread();
4653551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  ScopedJavaLocalRef<jstring> java_url =
4663551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      base::android::ConvertUTF8ToJavaString(env, url.spec());
4673551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  ScopedJavaLocalRef<jstring> java_title =
4683551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      base::android::ConvertUTF16ToJavaString(env, title);
4693551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  ScopedJavaLocalRef<jobject> java_bitmap;
4701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (icon_bitmap.getSize())
4711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    java_bitmap = gfx::ConvertToJavaBitmap(&icon_bitmap);
4724e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
4731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  Java_ShortcutHelper_addShortcut(
4741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      env,
4751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      base::android::GetApplicationContext(),
4761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      java_url.obj(),
4771320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      java_title.obj(),
4781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      java_bitmap.obj(),
4791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      r_value,
4801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      g_value,
4811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      b_value,
4821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      display == content::Manifest::DISPLAY_MODE_STANDALONE,
4831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      orientation);
4843551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
485