chromium/chrome/browser/ui/webui/ash/settings/pages/device/device_stylus_handler.cc

// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/ui/webui/ash/settings/pages/device/device_stylus_handler.h"

#include <memory>
#include <string>
#include <utility>
#include <vector>

#include "ash/public/cpp/stylus_utils.h"
#include "base/functional/bind.h"
#include "chrome/browser/apps/app_service/app_service_proxy.h"
#include "chrome/browser/apps/app_service/app_service_proxy_factory.h"
#include "chrome/browser/ash/app_list/arc/arc_app_utils.h"
#include "chrome/browser/ash/arc/arc_util.h"
#include "chrome/browser/profiles/profile.h"

namespace ash::settings {

namespace {

// Keys in objects passed to onNoteTakingAppsUpdated.
constexpr char kAppNameKey[] = "name";
constexpr char kAppIdKey[] = "value";
constexpr char kAppPreferredKey[] = "preferred";
constexpr char kAppLockScreenSupportKey[] = "lockScreenSupport";

}  // namespace

StylusHandler::StylusHandler() = default;
StylusHandler::~StylusHandler() = default;

void StylusHandler::RegisterMessages() {
  DCHECK(web_ui());

  // Note: initializeStylusSettings must be called before observers will be
  // added.
  web_ui()->RegisterMessageCallback(
      "initializeStylusSettings",
      base::BindRepeating(&StylusHandler::HandleInitialize,
                          base::Unretained(this)));
  web_ui()->RegisterMessageCallback(
      "requestNoteTakingApps",
      base::BindRepeating(&StylusHandler::HandleRequestApps,
                          base::Unretained(this)));
  web_ui()->RegisterMessageCallback(
      "setPreferredNoteTakingApp",
      base::BindRepeating(&StylusHandler::HandleSetPreferredNoteTakingApp,
                          base::Unretained(this)));
  web_ui()->RegisterMessageCallback(
      "setPreferredNoteTakingAppEnabledOnLockScreen",
      base::BindRepeating(
          &StylusHandler::HandleSetPreferredNoteTakingAppEnabledOnLockScreen,
          base::Unretained(this)));
  web_ui()->RegisterMessageCallback(
      "showPlayStoreApps",
      base::BindRepeating(&StylusHandler::HandleShowPlayStoreApps,
                          base::Unretained(this)));
}

void StylusHandler::OnJavascriptAllowed() {
  note_observation_.Observe(NoteTakingHelper::Get());
  input_observation_.Observe(ui::DeviceDataManager::GetInstance());
}

void StylusHandler::OnJavascriptDisallowed() {
  note_observation_.Reset();
  input_observation_.Reset();
}

void StylusHandler::OnAvailableNoteTakingAppsUpdated() {
  UpdateNoteTakingApps();
}

void StylusHandler::OnPreferredNoteTakingAppUpdated(Profile* profile) {
  if (Profile::FromWebUI(web_ui()) == profile) {
    UpdateNoteTakingApps();
  }
}

void StylusHandler::OnDeviceListsComplete() {
  SendHasStylus();
}

void StylusHandler::UpdateNoteTakingApps() {
  bool waiting_for_android = false;
  note_taking_app_ids_.clear();
  base::Value::List apps_list;

  NoteTakingHelper* helper = NoteTakingHelper::Get();
  if (helper->play_store_enabled() && !helper->android_apps_received()) {
    // If Play Store is enabled but not ready yet, let the JS know so it can
    // disable the menu and display an explanatory message.
    waiting_for_android = true;
  } else {
    std::vector<NoteTakingAppInfo> available_apps =
        helper->GetAvailableApps(Profile::FromWebUI(web_ui()));
    for (const NoteTakingAppInfo& info : available_apps) {
      apps_list.Append(base::Value::Dict()
                           .Set(kAppNameKey, info.name)
                           .Set(kAppIdKey, info.app_id)
                           .Set(kAppPreferredKey, info.preferred)
                           .Set(kAppLockScreenSupportKey,
                                static_cast<int>(info.lock_screen_support)));

      note_taking_app_ids_.insert(info.app_id);
    }
  }

  FireWebUIListener("onNoteTakingAppsUpdated", apps_list,
                    base::Value(waiting_for_android));
}

void StylusHandler::HandleRequestApps(const base::Value::List& unused_args) {
  AllowJavascript();
  UpdateNoteTakingApps();
}

void StylusHandler::HandleSetPreferredNoteTakingApp(
    const base::Value::List& args) {
  const std::string& app_id = args[0].GetString();

  // Sanity check: make sure that the ID we got back from WebUI is in the
  // currently-available set.
  if (!note_taking_app_ids_.count(app_id)) {
    LOG(ERROR) << "Got unknown note-taking-app ID \"" << app_id << "\"";
    return;
  }

  NoteTakingHelper::Get()->SetPreferredApp(Profile::FromWebUI(web_ui()),
                                           app_id);
}

void StylusHandler::HandleSetPreferredNoteTakingAppEnabledOnLockScreen(
    const base::Value::List& args) {
  bool enabled = false;
  CHECK(args[0].is_bool());
  enabled = args[0].GetBool();

  NoteTakingHelper::Get()->SetPreferredAppEnabledOnLockScreen(
      Profile::FromWebUI(web_ui()), enabled);
}

void StylusHandler::HandleInitialize(const base::Value::List& args) {
  AllowJavascript();
  if (ui::DeviceDataManager::GetInstance()->AreDeviceListsComplete()) {
    SendHasStylus();
  }
}

void StylusHandler::SendHasStylus() {
  DCHECK(ui::DeviceDataManager::GetInstance()->AreDeviceListsComplete());
  FireWebUIListener("has-stylus-changed",
                    base::Value(stylus_utils::HasStylusInput()));
}

void StylusHandler::HandleShowPlayStoreApps(const base::Value::List& args) {
  const std::string& apps_url = !args.empty() ? args[0].GetString() : "";
  Profile* profile = Profile::FromWebUI(web_ui());
  if (!arc::IsArcAllowedForProfile(profile)) {
    VLOG(1) << "ARC is not enabled for this profile";
    return;
  }

  DCHECK(
      apps::AppServiceProxyFactory::IsAppServiceAvailableForProfile(profile));
  apps::AppServiceProxyFactory::GetForProfile(profile)->LaunchAppWithUrl(
      arc::kPlayStoreAppId, ui::EF_NONE, GURL(apps_url),
      apps::LaunchSource::kFromChromeInternal);
}

}  // namespace ash::settings