| Index: chrome/browser/chromeos/arc/voice_interaction/arc_voice_interaction_framework_service.cc
|
| diff --git a/chrome/browser/chromeos/arc/voice_interaction/arc_voice_interaction_framework_service.cc b/chrome/browser/chromeos/arc/voice_interaction/arc_voice_interaction_framework_service.cc
|
| index 4362d00abbd403e1e4e3b8ef35abe162534a6db7..0f11ecec3383a175c0a9f564ca54111d6b3dfc64 100644
|
| --- a/chrome/browser/chromeos/arc/voice_interaction/arc_voice_interaction_framework_service.cc
|
| +++ b/chrome/browser/chromeos/arc/voice_interaction/arc_voice_interaction_framework_service.cc
|
| @@ -11,10 +11,12 @@
|
| #include "ash/public/cpp/shell_window_ids.h"
|
| #include "ash/shell.h"
|
| #include "base/bind.h"
|
| +#include "base/callback.h"
|
| #include "base/command_line.h"
|
| #include "base/containers/flat_set.h"
|
| #include "base/logging.h"
|
| #include "base/memory/ref_counted.h"
|
| +#include "base/metrics/histogram_macros.h"
|
| #include "base/metrics/user_metrics.h"
|
| #include "base/metrics/user_metrics_action.h"
|
| #include "base/task_scheduler/post_task.h"
|
| @@ -32,6 +34,7 @@
|
| #include "ui/compositor/layer.h"
|
| #include "ui/compositor/layer_owner.h"
|
| #include "ui/compositor/layer_tree_owner.h"
|
| +#include "ui/gfx/geometry/rect.h"
|
| #include "ui/gfx/image/image.h"
|
| #include "ui/gfx/image/image_util.h"
|
| #include "ui/gfx/native_widget_types.h"
|
| @@ -46,6 +49,17 @@ namespace {
|
|
|
| using LayerSet = base::flat_set<const ui::Layer*>;
|
|
|
| +// Time out for a context query from container since user initiated
|
| +// interaction. This must be strictly less than
|
| +// kMaxTimeSinceUserInteractionForHistogram so that the histogram
|
| +// could cover the range of normal operations.
|
| +constexpr base::TimeDelta kAllowedTimeSinceUserInteraction =
|
| + base::TimeDelta::FromSeconds(2);
|
| +constexpr base::TimeDelta kMaxTimeSinceUserInteractionForHistogram =
|
| + base::TimeDelta::FromSeconds(5);
|
| +
|
| +constexpr int32_t kContextRequestMaxRemainingCount = 2;
|
| +
|
| void ScreenshotCallback(
|
| const mojom::VoiceInteractionFrameworkHost::CaptureFocusedWindowCallback&
|
| callback,
|
| @@ -185,13 +199,9 @@ bool ArcVoiceInteractionFrameworkService::AcceleratorPressed(
|
|
|
| // Temporary, used for debugging.
|
| // Does not take into account or update the palette state.
|
| - mojom::VoiceInteractionFrameworkInstance* framework_instance =
|
| - ARC_GET_INSTANCE_FOR_METHOD(
|
| - arc_bridge_service()->voice_interaction_framework(),
|
| - SetMetalayerVisibility);
|
| - DCHECK(framework_instance);
|
| - framework_instance->SetMetalayerVisibility(true);
|
| -
|
| + // Explicitly call ShowMetalayer() to take into account user interaction
|
| + // initiations.
|
| + ShowMetalayer(base::Bind([]() {}));
|
| return true;
|
| }
|
|
|
| @@ -203,6 +213,12 @@ bool ArcVoiceInteractionFrameworkService::CanHandleAccelerators() const {
|
| void ArcVoiceInteractionFrameworkService::CaptureFocusedWindow(
|
| const CaptureFocusedWindowCallback& callback) {
|
| DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
|
| +
|
| + if (!ValidateTimeSinceUserInteraction()) {
|
| + callback.Run(std::vector<uint8_t>{});
|
| + return;
|
| + }
|
| +
|
| aura::Window* window =
|
| ash::Shell::Get()->activation_client()->GetActiveWindow();
|
|
|
| @@ -220,6 +236,12 @@ void ArcVoiceInteractionFrameworkService::CaptureFocusedWindow(
|
| void ArcVoiceInteractionFrameworkService::CaptureFullscreen(
|
| const CaptureFullscreenCallback& callback) {
|
| DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
|
| +
|
| + if (!ValidateTimeSinceUserInteraction()) {
|
| + callback.Run(std::vector<uint8_t>{});
|
| + return;
|
| + }
|
| +
|
| // Since ARC currently only runs in primary display, we restrict
|
| // the screenshot to it.
|
| aura::Window* window = ash::Shell::GetPrimaryRootWindow();
|
| @@ -257,7 +279,17 @@ void ArcVoiceInteractionFrameworkService::ShowMetalayer(
|
| LOG(ERROR) << "Metalayer is already enabled";
|
| return;
|
| }
|
| - metalayer_closed_callback_ = closed;
|
| + metalayer_closed_callback_ = base::Bind(
|
| + [](const base::Callback<bool()>& init, const base::Closure& closed) {
|
| + // Initiate user interaction when metalayer disappears.
|
| + if (init.Run())
|
| + closed.Run();
|
| + },
|
| + base::Bind(&ArcVoiceInteractionFrameworkService::InitiateUserInteraction,
|
| + // metalayer_closed_callback_ is owned and used inside
|
| + // ArcVoiceInteractionFrameworkService's member functions.
|
| + base::Unretained(this)),
|
| + closed);
|
| SetMetalayerVisibility(true);
|
| }
|
|
|
| @@ -271,19 +303,6 @@ void ArcVoiceInteractionFrameworkService::HideMetalayer() {
|
| SetMetalayerVisibility(false);
|
| }
|
|
|
| -void ArcVoiceInteractionFrameworkService::StartVoiceInteractionSession() {
|
| - DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
|
| - mojom::VoiceInteractionFrameworkInstance* framework_instance =
|
| - ARC_GET_INSTANCE_FOR_METHOD(
|
| - arc_bridge_service()->voice_interaction_framework(),
|
| - StartVoiceInteractionSession);
|
| - if (!framework_instance) {
|
| - arc::SetArcCpuRestriction(false);
|
| - return;
|
| - }
|
| - framework_instance->StartVoiceInteractionSession();
|
| -}
|
| -
|
| void ArcVoiceInteractionFrameworkService::SetMetalayerVisibility(bool visible) {
|
| DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
|
| mojom::VoiceInteractionFrameworkInstance* framework_instance =
|
| @@ -298,4 +317,77 @@ void ArcVoiceInteractionFrameworkService::SetMetalayerVisibility(bool visible) {
|
| framework_instance->SetMetalayerVisibility(visible);
|
| }
|
|
|
| +void ArcVoiceInteractionFrameworkService::StartSessionFromUserInteraction(
|
| + const gfx::Rect& rect) {
|
| + DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
|
| +
|
| + if (!arc_bridge_service()->voice_interaction_framework()->has_instance()) {
|
| + SetArcCpuRestriction(false);
|
| + return;
|
| + }
|
| +
|
| + if (!InitiateUserInteraction())
|
| + return;
|
| +
|
| + if (rect.IsEmpty()) {
|
| + mojom::VoiceInteractionFrameworkInstance* framework_instance =
|
| + ARC_GET_INSTANCE_FOR_METHOD(
|
| + arc_bridge_service()->voice_interaction_framework(),
|
| + StartVoiceInteractionSession);
|
| + DCHECK(framework_instance);
|
| + framework_instance->StartVoiceInteractionSession();
|
| + } else {
|
| + mojom::VoiceInteractionFrameworkInstance* framework_instance =
|
| + ARC_GET_INSTANCE_FOR_METHOD(
|
| + arc_bridge_service()->voice_interaction_framework(),
|
| + StartVoiceInteractionSessionForRegion);
|
| + DCHECK(framework_instance);
|
| + framework_instance->StartVoiceInteractionSessionForRegion(rect);
|
| + }
|
| +}
|
| +
|
| +bool ArcVoiceInteractionFrameworkService::ValidateTimeSinceUserInteraction() {
|
| + DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
|
| +
|
| + if (!context_request_remaining_count_) {
|
| + // Allowed number of requests used up. But we still have additional
|
| + // requests. It's likely that there is something malicious going on.
|
| + LOG(ERROR) << "Illegal context request from container.";
|
| + UMA_HISTOGRAM_BOOLEAN("VoiceInteraction.IllegalContextRequest", true);
|
| + return false;
|
| + }
|
| + auto elapsed = base::TimeTicks::Now() - user_interaction_start_time_;
|
| + elapsed = elapsed > kMaxTimeSinceUserInteractionForHistogram
|
| + ? kMaxTimeSinceUserInteractionForHistogram
|
| + : elapsed;
|
| +
|
| + UMA_HISTOGRAM_CUSTOM_COUNTS(
|
| + "VoiceInteraction.UserInteractionToRequestArrival",
|
| + elapsed.InMilliseconds(), 1,
|
| + kMaxTimeSinceUserInteractionForHistogram.InMilliseconds(), 20);
|
| +
|
| + if (elapsed > kAllowedTimeSinceUserInteraction) {
|
| + LOG(ERROR) << "Timed out since last user interaction.";
|
| + context_request_remaining_count_ = 0;
|
| + return false;
|
| + }
|
| +
|
| + context_request_remaining_count_--;
|
| + return true;
|
| +}
|
| +
|
| +bool ArcVoiceInteractionFrameworkService::InitiateUserInteraction() {
|
| + auto start_time = base::TimeTicks::Now();
|
| + if ((start_time - user_interaction_start_time_) <
|
| + kAllowedTimeSinceUserInteraction &&
|
| + context_request_remaining_count_) {
|
| + // If next request starts too soon and there is an active session in action,
|
| + // we should drop it.
|
| + return false;
|
| + }
|
| + user_interaction_start_time_ = start_time;
|
| + context_request_remaining_count_ = kContextRequestMaxRemainingCount;
|
| + return true;
|
| +}
|
| +
|
| } // namespace arc
|
|
|