chromium/chromeos/ash/services/libassistant/display_connection.cc

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

#include "chromeos/ash/services/libassistant/display_connection.h"

#include <sstream>

#include "base/check.h"
#include "base/logging.h"
#include "base/task/sequenced_task_runner.h"
#include "chromeos/ash/services/libassistant/grpc/assistant_client.h"
#include "chromeos/assistant/internal/proto/shared/proto/v2/display_interface.pb.h"

namespace ash::libassistant {

DisplayConnection::DisplayConnection(DisplayConnectionObserver* observer,
                                     bool feedback_ui_enabled)
    : observer_(observer),
      feedback_ui_enabled_(feedback_ui_enabled),
      task_runner_(base::SequencedTaskRunner::GetCurrentDefault()) {
  DCHECK(observer_);
}

DisplayConnection::~DisplayConnection() = default;

void DisplayConnection::OnGrpcMessage(
    const ::assistant::api::OnAssistantDisplayEventRequest& request) {
  auto& assistant_display_event = request.event();

  DCHECK(assistant_display_event.has_on_assistant_event());
  DCHECK(
      assistant_display_event.on_assistant_event().has_assistant_event_bytes());
  DVLOG(1) << "AssistantDisplayEventObserver received GrpcMessage.";

  const std::string& assistant_event_bytes =
      assistant_display_event.on_assistant_event().assistant_event_bytes();

  ::assistant::display::AssistantEvent event;
  if (!event.ParseFromString(assistant_event_bytes)) {
    LOG(ERROR) << "Unable to parse assistant event";
    return;
  }

  if (event.has_speech_level_event()) {
    task_runner_->PostTask(
        FROM_HERE,
        base::BindOnce(&DisplayConnectionObserver::OnSpeechLevelUpdated,
                       base::Unretained(observer_),
                       event.speech_level_event().speech_level()));
  }
}

void DisplayConnection::SetAssistantClient(AssistantClient* assistant_client) {
  assistant_client_ = assistant_client;
}

void DisplayConnection::SetArcPlayStoreEnabled(bool enabled) {
  arc_play_store_enabled_ = enabled;
  SendDisplayRequest();
}

void DisplayConnection::SetDeviceAppsEnabled(bool enabled) {
  // For now we don't handle disabling the device apps bit, since we do not have
  // a way to get the bit changes. We only sync the bit at Service start post
  // login.
  // If user accept the whole activity control flow later we update the bit to
  // true.
  DCHECK(enabled || !device_apps_enabled_);
  if (device_apps_enabled_ == enabled)
    return;
  device_apps_enabled_ = enabled;
  SendDisplayRequest();
}

void DisplayConnection::SetAssistantContextEnabled(bool enabled) {
  if (related_info_enabled_ == enabled)
    return;
  related_info_enabled_ = enabled;
  SendDisplayRequest();
}

void DisplayConnection::OnAndroidAppListRefreshed(
    const std::vector<assistant::AndroidAppInfo>& apps_info) {
  apps_info_ = apps_info;
  SendDisplayRequest();
}

void DisplayConnection::SendDisplayRequest() {
  if (!assistant_client_) {
    LOG(ERROR) << "Can't send DisplayRequest before assistant client is set.";
    return;
  }

  ::assistant::display::DisplayRequest display_request;
  FillDisplayRequest(display_request);

  ::assistant::api::OnDisplayRequestRequest request;
  request.set_display_request_bytes(display_request.SerializeAsString());
  assistant_client_->SendDisplayRequest(request);
}

void DisplayConnection::FillDisplayRequest(
    ::assistant::display::DisplayRequest& dr) {
  auto* set_capabilities_request = dr.mutable_set_capabilities_request();
  auto* screen_capabilities =
      set_capabilities_request->mutable_screen_capabilities_to_merge();
  auto* resolution = screen_capabilities->mutable_resolution();
  // TODO(b/111841376): Set actual chromeos screen resolution and reset it when
  // resolution is changed.
  resolution->set_width_px(300);
  resolution->set_height_px(200);
  set_capabilities_request->set_server_generated_feedback_chips_enabled(
      feedback_ui_enabled_);
  set_capabilities_request->set_web_browser_supported(true);
  set_capabilities_request->mutable_supported_provider_types()
      ->add_supported_types(
          ::assistant::api::core_types::ProviderType::WEB_PROVIDER);

  if (arc_play_store_enabled_ && device_apps_enabled_) {
    set_capabilities_request->mutable_supported_provider_types()
        ->add_supported_types(
            ::assistant::api::core_types::ProviderType::ANDROID_APP);

    for (auto& app_info : apps_info_) {
      auto* android_app_info = set_capabilities_request->add_app_capabilities()
                                   ->mutable_provider()
                                   ->mutable_android_app_info();
      android_app_info->set_package_name(app_info.package_name);
      android_app_info->set_app_version(app_info.version);
      android_app_info->set_localized_app_name(app_info.localized_app_name);
      // android_intent are not set here since server will exclude app info
      // with intent field set.
    }
  }

  set_capabilities_request->mutable_supported_features()
      ->set_media_session_detection(
          related_info_enabled_
              ? ::assistant::api::RELIABLE_MEDIA_SESSION_DETECTION
              : ::assistant::api::
                    MEDIA_SESSION_DETECTION_DISABLED_SCREEN_CONTEXT);
}

}  // namespace ash::libassistant