| // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.h" |
| |
| #include <algorithm> |
| #include <deque> |
| #include <map> |
| #include <memory> |
| #include <set> |
| #include <sstream> |
| #include <utility> |
| |
| #include "ash/constants/app_types.h" |
| #include "ash/public/cpp/accelerators.h" |
| #include "ash/public/cpp/accessibility_controller.h" |
| #include "ash/public/cpp/ambient/ambient_ui_model.h" |
| #include "ash/public/cpp/app_list/app_list_types.h" |
| #include "ash/public/cpp/ash_pref_names.h" |
| #include "ash/public/cpp/autotest_ambient_api.h" |
| #include "ash/public/cpp/autotest_desks_api.h" |
| #include "ash/public/cpp/autotest_private_api_utils.h" |
| #include "ash/public/cpp/desks_helper.h" |
| #include "ash/public/cpp/login_screen.h" |
| #include "ash/public/cpp/metrics_util.h" |
| #include "ash/public/cpp/overview_test_api.h" |
| #include "ash/public/cpp/shelf_item.h" |
| #include "ash/public/cpp/shelf_model.h" |
| #include "ash/public/cpp/shelf_prefs.h" |
| #include "ash/public/cpp/shelf_test_api.h" |
| #include "ash/public/cpp/shelf_types.h" |
| #include "ash/public/cpp/shelf_ui_info.h" |
| #include "ash/public/cpp/split_view_test_api.h" |
| #include "ash/public/cpp/tablet_mode.h" |
| #include "ash/public/cpp/window_properties.h" |
| #include "ash/rotator/screen_rotation_animator.h" |
| #include "ash/shell.h" |
| #include "ash/wm/wm_event.h" |
| #include "base/base64.h" |
| #include "base/bind.h" |
| #include "base/feature_list.h" |
| #include "base/json/json_reader.h" |
| #include "base/lazy_instance.h" |
| #include "base/no_destructor.h" |
| #include "base/numerics/safe_conversions.h" |
| #include "base/run_loop.h" |
| #include "base/scoped_observation.h" |
| #include "base/strings/strcat.h" |
| #include "base/strings/string_number_conversions.h" |
| #include "base/strings/stringprintf.h" |
| #include "base/task/post_task.h" |
| #include "base/threading/sequenced_task_runner_handle.h" |
| #include "base/threading/thread_task_runner_handle.h" |
| #include "base/time/time.h" |
| #include "base/values.h" |
| #include "build/build_config.h" |
| #include "chrome/app/chrome_command_ids.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/arc/arc_util.h" |
| #include "chrome/browser/ash/arc/session/arc_session_manager.h" |
| #include "chrome/browser/ash/arc/tracing/arc_app_performance_tracing.h" |
| #include "chrome/browser/ash/arc/tracing/arc_app_performance_tracing_session.h" |
| #include "chrome/browser/ash/assistant/assistant_util.h" |
| #include "chrome/browser/ash/borealis/borealis_installer.h" |
| #include "chrome/browser/ash/borealis/borealis_metrics.h" |
| #include "chrome/browser/ash/borealis/borealis_service.h" |
| #include "chrome/browser/ash/crostini/crostini_export_import.h" |
| #include "chrome/browser/ash/crostini/crostini_features.h" |
| #include "chrome/browser/ash/crostini/crostini_installer.h" |
| #include "chrome/browser/ash/crostini/crostini_manager.h" |
| #include "chrome/browser/ash/crostini/crostini_pref_names.h" |
| #include "chrome/browser/ash/crostini/crostini_util.h" |
| #include "chrome/browser/ash/guest_os/guest_os_registry_service.h" |
| #include "chrome/browser/ash/guest_os/guest_os_registry_service_factory.h" |
| #include "chrome/browser/ash/login/lock/screen_locker.h" |
| #include "chrome/browser/ash/plugin_vm/plugin_vm_installer.h" |
| #include "chrome/browser/ash/plugin_vm/plugin_vm_installer_factory.h" |
| #include "chrome/browser/ash/plugin_vm/plugin_vm_pref_names.h" |
| #include "chrome/browser/ash/plugin_vm/plugin_vm_util.h" |
| #include "chrome/browser/ash/settings/cros_settings.h" |
| #include "chrome/browser/ash/settings/stats_reporting_controller.h" |
| #include "chrome/browser/ash/system/input_device_settings.h" |
| #include "chrome/browser/banners/app_banner_manager_desktop.h" |
| #include "chrome/browser/browser_process.h" |
| #include "chrome/browser/browser_process_platform_part.h" |
| #include "chrome/browser/chromeos/file_manager/path_util.h" |
| #include "chrome/browser/chromeos/printing/cups_printers_manager.h" |
| #include "chrome/browser/chromeos/printing/cups_printers_manager_factory.h" |
| #include "chrome/browser/extensions/extension_service.h" |
| #include "chrome/browser/lifetime/application_lifetime.h" |
| #include "chrome/browser/policy/chrome_policy_conversions_client.h" |
| #include "chrome/browser/profiles/profile.h" |
| #include "chrome/browser/profiles/profile_manager.h" |
| #include "chrome/browser/ui/app_list/arc/arc_app_list_prefs.h" |
| #include "chrome/browser/ui/app_list/arc/arc_app_utils.h" |
| #include "chrome/browser/ui/ash/shelf/chrome_shelf_controller.h" |
| #include "chrome/browser/ui/ash/shelf/shelf_spinner_controller.h" |
| #include "chrome/browser/ui/aura/accessibility/automation_manager_aura.h" |
| #include "chrome/browser/ui/browser.h" |
| #include "chrome/browser/ui/browser_commands.h" |
| #include "chrome/browser/ui/browser_dialogs.h" |
| #include "chrome/browser/ui/browser_list.h" |
| #include "chrome/browser/ui/browser_tabstrip.h" |
| #include "chrome/browser/ui/browser_window.h" |
| #include "chrome/browser/ui/toolbar/app_menu_model.h" |
| #include "chrome/browser/ui/views/crostini/crostini_uninstaller_view.h" |
| #include "chrome/browser/ui/views/plugin_vm/plugin_vm_installer_view.h" |
| #include "chrome/browser/ui/web_applications/system_web_app_ui_utils.h" |
| #include "chrome/browser/ui/webui/chromeos/crostini_installer/crostini_installer_dialog.h" |
| #include "chrome/browser/ui/webui/chromeos/crostini_installer/crostini_installer_ui.h" |
| #include "chrome/browser/web_applications/components/app_registrar.h" |
| #include "chrome/browser/web_applications/components/app_registrar_observer.h" |
| #include "chrome/browser/web_applications/components/web_app_provider_base.h" |
| #include "chrome/browser/web_applications/system_web_apps/system_web_app_manager.h" |
| #include "chrome/browser/web_applications/web_app_provider.h" |
| #include "chrome/common/extensions/api/autotest_private.h" |
| #include "chrome/common/pref_names.h" |
| #include "chromeos/dbus/dbus_thread_manager.h" |
| #include "chromeos/dbus/session_manager/session_manager_client.h" |
| #include "chromeos/printing/printer_configuration.h" |
| #include "chromeos/services/assistant/public/cpp/assistant_prefs.h" |
| #include "chromeos/services/assistant/public/cpp/assistant_service.h" |
| #include "chromeos/services/machine_learning/public/cpp/service_connection.h" |
| #include "chromeos/settings/cros_settings_names.h" |
| #include "chromeos/ui/base/window_properties.h" |
| #include "chromeos/ui/frame/default_frame_header.h" |
| #include "chromeos/ui/frame/frame_header.h" |
| #include "chromeos/ui/frame/immersive/immersive_fullscreen_controller.h" |
| #include "components/arc/arc_prefs.h" |
| #include "components/arc/metrics/arc_metrics_constants.h" |
| #include "components/full_restore/full_restore_utils.h" |
| #include "components/policy/core/browser/policy_conversions.h" |
| #include "components/policy/core/common/policy_service.h" |
| #include "components/services/app_service/public/mojom/types.mojom.h" |
| #include "components/user_manager/user_manager.h" |
| #include "components/webapps/browser/banners/app_banner_manager.h" |
| #include "content/public/browser/browser_thread.h" |
| #include "content/public/browser/navigation_controller.h" |
| #include "content/public/browser/tracing_controller.h" |
| #include "content/public/browser/web_contents.h" |
| #include "extensions/browser/event_router.h" |
| #include "extensions/browser/extension_action.h" |
| #include "extensions/browser/extension_action_manager.h" |
| #include "extensions/browser/extension_function.h" |
| #include "extensions/browser/extension_function_registry.h" |
| #include "extensions/browser/extension_registry.h" |
| #include "extensions/browser/extension_system.h" |
| #include "extensions/browser/extension_util.h" |
| #include "extensions/common/api/extension_action/action_info.h" |
| #include "extensions/common/manifest_handlers/background_info.h" |
| #include "extensions/common/manifest_handlers/options_page_info.h" |
| #include "extensions/common/permissions/api_permission_set.h" |
| #include "extensions/common/permissions/permission_set.h" |
| #include "extensions/common/permissions/permissions_data.h" |
| #include "mojo/public/cpp/bindings/receiver.h" |
| #include "net/base/filename_util.h" |
| #include "third_party/abseil-cpp/absl/types/optional.h" |
| #include "ui/aura/client/aura_constants.h" |
| #include "ui/aura/env.h" |
| #include "ui/aura/window.h" |
| #include "ui/aura/window_observer.h" |
| #include "ui/aura/window_tree_host.h" |
| #include "ui/base/clipboard/clipboard.h" |
| #include "ui/base/clipboard/scoped_clipboard_writer.h" |
| #include "ui/base/ime/chromeos/ime_bridge.h" |
| #include "ui/base/ui_base_features.h" |
| #include "ui/compositor/layer.h" |
| #include "ui/compositor/throughput_tracker.h" |
| #include "ui/compositor/throughput_tracker_host.h" |
| #include "ui/display/display.h" |
| #include "ui/display/screen.h" |
| #include "ui/events/event_constants.h" |
| #include "ui/events/types/event_type.h" |
| #include "ui/gfx/geometry/point_conversions.h" |
| #include "ui/message_center/message_center.h" |
| #include "ui/message_center/notification_list.h" |
| #include "ui/message_center/public/cpp/notification.h" |
| #include "ui/message_center/public/cpp/notification_types.h" |
| #include "ui/ozone/public/ozone_platform.h" |
| #include "ui/ozone/public/system_input_injector.h" |
| #include "ui/views/widget/widget.h" |
| #include "ui/wm/core/coordinate_conversion.h" |
| #include "ui/wm/core/cursor_manager.h" |
| #include "ui/wm/core/window_util.h" |
| #include "ui/wm/public/activation_client.h" |
| #include "url/gurl.h" |
| |
| using extensions::mojom::ManifestLocation; |
| |
| namespace extensions { |
| namespace { |
| |
| using chromeos::PrinterClass; |
| |
| constexpr char kCrostiniNotAvailableForCurrentUserError[] = |
| "Crostini is not available for the current user"; |
| |
| int AccessArray(const volatile int arr[], const volatile int* index) { |
| return arr[*index]; |
| } |
| |
| base::ListValue GetHostPermissions(const Extension* ext, bool effective_perm) { |
| const PermissionsData* permissions_data = ext->permissions_data(); |
| |
| const URLPatternSet* pattern_set = nullptr; |
| URLPatternSet effective_hosts; |
| if (effective_perm) { |
| effective_hosts = permissions_data->GetEffectiveHostPermissions(); |
| pattern_set = &effective_hosts; |
| } else { |
| pattern_set = &permissions_data->active_permissions().explicit_hosts(); |
| } |
| |
| base::ListValue permissions; |
| for (const auto& perm : *pattern_set) |
| permissions.AppendString(perm.GetAsString()); |
| |
| return permissions; |
| } |
| |
| base::ListValue GetAPIPermissions(const Extension* ext) { |
| base::ListValue permissions; |
| std::set<std::string> perm_list = |
| ext->permissions_data()->active_permissions().GetAPIsAsStrings(); |
| for (std::set<std::string>::const_iterator perm = perm_list.begin(); |
| perm != perm_list.end(); ++perm) { |
| permissions.AppendString(*perm); |
| } |
| return permissions; |
| } |
| |
| bool IsTestMode(content::BrowserContext* context) { |
| return AutotestPrivateAPI::GetFactoryInstance()->Get(context)->test_mode(); |
| } |
| |
| std::string ConvertToString(message_center::NotificationType type) { |
| switch (type) { |
| case message_center::NOTIFICATION_TYPE_SIMPLE: |
| return "simple"; |
| case message_center::NOTIFICATION_TYPE_BASE_FORMAT: |
| return "base_format"; |
| case message_center::NOTIFICATION_TYPE_IMAGE: |
| return "image"; |
| case message_center::NOTIFICATION_TYPE_MULTIPLE: |
| return "multiple"; |
| case message_center::NOTIFICATION_TYPE_PROGRESS: |
| return "progress"; |
| case message_center::NOTIFICATION_TYPE_CUSTOM: |
| return "custom"; |
| } |
| return "unknown"; |
| } |
| |
| std::unique_ptr<base::DictionaryValue> MakeDictionaryFromNotification( |
| const message_center::Notification& notification) { |
| auto result = std::make_unique<base::DictionaryValue>(); |
| result->SetString("id", notification.id()); |
| result->SetString("type", ConvertToString(notification.type())); |
| result->SetString("title", notification.title()); |
| result->SetString("message", notification.message()); |
| result->SetInteger("priority", notification.priority()); |
| result->SetInteger("progress", notification.progress()); |
| return result; |
| } |
| |
| std::string GetPrinterType(PrinterClass type) { |
| switch (type) { |
| case PrinterClass::kSaved: |
| return "configured"; |
| case PrinterClass::kEnterprise: |
| return "enterprise"; |
| case PrinterClass::kAutomatic: |
| return "automatic"; |
| case PrinterClass::kDiscovered: |
| return "discovered"; |
| default: |
| return "unknown"; |
| } |
| } |
| |
| api::autotest_private::ShelfItemType GetShelfItemType(ash::ShelfItemType type) { |
| switch (type) { |
| case ash::TYPE_PINNED_APP: |
| return api::autotest_private::ShelfItemType::SHELF_ITEM_TYPE_PINNEDAPP; |
| case ash::TYPE_BROWSER_SHORTCUT: |
| return api::autotest_private::ShelfItemType:: |
| SHELF_ITEM_TYPE_BROWSERSHORTCUT; |
| case ash::TYPE_APP: |
| return api::autotest_private::ShelfItemType::SHELF_ITEM_TYPE_APP; |
| case ash::TYPE_UNPINNED_BROWSER_SHORTCUT: |
| return api::autotest_private::ShelfItemType:: |
| SHELF_ITEM_TYPE_UNPINNEDBROWSERSHORTCUT; |
| case ash::TYPE_DIALOG: |
| return api::autotest_private::ShelfItemType::SHELF_ITEM_TYPE_DIALOG; |
| case ash::TYPE_UNDEFINED: |
| return api::autotest_private::ShelfItemType::SHELF_ITEM_TYPE_NONE; |
| } |
| NOTREACHED(); |
| return api::autotest_private::ShelfItemType::SHELF_ITEM_TYPE_NONE; |
| } |
| |
| api::autotest_private::ShelfItemStatus GetShelfItemStatus( |
| ash::ShelfItemStatus status) { |
| switch (status) { |
| case ash::STATUS_CLOSED: |
| return api::autotest_private::ShelfItemStatus::SHELF_ITEM_STATUS_CLOSED; |
| case ash::STATUS_RUNNING: |
| return api::autotest_private::ShelfItemStatus::SHELF_ITEM_STATUS_RUNNING; |
| case ash::STATUS_ATTENTION: |
| return api::autotest_private::ShelfItemStatus:: |
| SHELF_ITEM_STATUS_ATTENTION; |
| } |
| NOTREACHED(); |
| return api::autotest_private::ShelfItemStatus::SHELF_ITEM_STATUS_NONE; |
| } |
| |
| api::autotest_private::AppType GetAppType(apps::mojom::AppType type) { |
| switch (type) { |
| case apps::mojom::AppType::kArc: |
| return api::autotest_private::AppType::APP_TYPE_ARC; |
| case apps::mojom::AppType::kBuiltIn: |
| return api::autotest_private::AppType::APP_TYPE_BUILTIN; |
| case apps::mojom::AppType::kCrostini: |
| return api::autotest_private::AppType::APP_TYPE_CROSTINI; |
| case apps::mojom::AppType::kExtension: |
| return api::autotest_private::AppType::APP_TYPE_EXTENSION; |
| case apps::mojom::AppType::kPluginVm: |
| return api::autotest_private::AppType::APP_TYPE_PLUGINVM; |
| case apps::mojom::AppType::kWeb: |
| case apps::mojom::AppType::kSystemWeb: |
| return api::autotest_private::AppType::APP_TYPE_WEB; |
| case apps::mojom::AppType::kUnknown: |
| return api::autotest_private::AppType::APP_TYPE_NONE; |
| case apps::mojom::AppType::kMacOs: |
| return api::autotest_private::AppType::APP_TYPE_MACOS; |
| case apps::mojom::AppType::kStandaloneBrowser: |
| return api::autotest_private::AppType::APP_TYPE_STANDALONEBROWSER; |
| case apps::mojom::AppType::kRemote: |
| return api::autotest_private::AppType::APP_TYPE_REMOTE; |
| case apps::mojom::AppType::kBorealis: |
| return api::autotest_private::AppType::APP_TYPE_BOREALIS; |
| } |
| NOTREACHED(); |
| return api::autotest_private::AppType::APP_TYPE_NONE; |
| } |
| |
| api::autotest_private::AppInstallSource GetAppInstallSource( |
| apps::mojom::InstallSource source) { |
| switch (source) { |
| case apps::mojom::InstallSource::kUnknown: |
| return api::autotest_private::AppInstallSource:: |
| APP_INSTALL_SOURCE_UNKNOWN; |
| case apps::mojom::InstallSource::kSystem: |
| return api::autotest_private::AppInstallSource::APP_INSTALL_SOURCE_SYSTEM; |
| case apps::mojom::InstallSource::kPolicy: |
| return api::autotest_private::AppInstallSource::APP_INSTALL_SOURCE_POLICY; |
| case apps::mojom::InstallSource::kOem: |
| return api::autotest_private::AppInstallSource::APP_INSTALL_SOURCE_OEM; |
| case apps::mojom::InstallSource::kDefault: |
| return api::autotest_private::AppInstallSource:: |
| APP_INSTALL_SOURCE_DEFAULT; |
| case apps::mojom::InstallSource::kSync: |
| return api::autotest_private::AppInstallSource::APP_INSTALL_SOURCE_SYNC; |
| case apps::mojom::InstallSource::kUser: |
| return api::autotest_private::AppInstallSource::APP_INSTALL_SOURCE_USER; |
| } |
| NOTREACHED(); |
| return api::autotest_private::AppInstallSource::APP_INSTALL_SOURCE_NONE; |
| } |
| |
| api::autotest_private::AppWindowType GetAppWindowType(ash::AppType type) { |
| switch (type) { |
| case ash::AppType::ARC_APP: |
| return api::autotest_private::AppWindowType::APP_WINDOW_TYPE_ARCAPP; |
| case ash::AppType::SYSTEM_APP: |
| return api::autotest_private::AppWindowType::APP_WINDOW_TYPE_SYSTEMAPP; |
| case ash::AppType::CROSTINI_APP: |
| return api::autotest_private::AppWindowType::APP_WINDOW_TYPE_CROSTINIAPP; |
| case ash::AppType::CHROME_APP: |
| return api::autotest_private::AppWindowType::APP_WINDOW_TYPE_EXTENSIONAPP; |
| case ash::AppType::BROWSER: |
| return api::autotest_private::AppWindowType::APP_WINDOW_TYPE_BROWSER; |
| case ash::AppType::LACROS: |
| return api::autotest_private::AppWindowType::APP_WINDOW_TYPE_LACROS; |
| case ash::AppType::NON_APP: |
| return api::autotest_private::AppWindowType::APP_WINDOW_TYPE_NONE; |
| // TODO(oshima): Investigate if we want to have "extension" type. |
| } |
| NOTREACHED(); |
| return api::autotest_private::AppWindowType::APP_WINDOW_TYPE_NONE; |
| } |
| |
| api::autotest_private::AppReadiness GetAppReadiness( |
| apps::mojom::Readiness readiness) { |
| switch (readiness) { |
| case apps::mojom::Readiness::kReady: |
| return api::autotest_private::AppReadiness::APP_READINESS_READY; |
| case apps::mojom::Readiness::kDisabledByBlocklist: |
| return api::autotest_private::AppReadiness:: |
| APP_READINESS_DISABLEDBYBLACKLIST; |
| case apps::mojom::Readiness::kDisabledByPolicy: |
| return api::autotest_private::AppReadiness:: |
| APP_READINESS_DISABLEDBYPOLICY; |
| case apps::mojom::Readiness::kDisabledByUser: |
| return api::autotest_private::AppReadiness::APP_READINESS_DISABLEDBYUSER; |
| case apps::mojom::Readiness::kTerminated: |
| return api::autotest_private::AppReadiness::APP_READINESS_TERMINATED; |
| case apps::mojom::Readiness::kUninstalledByUser: |
| return api::autotest_private::AppReadiness:: |
| APP_READINESS_UNINSTALLEDBYUSER; |
| case apps::mojom::Readiness::kRemoved: |
| return api::autotest_private::AppReadiness::APP_READINESS_REMOVED; |
| case apps::mojom::Readiness::kUninstalledByMigration: |
| return api::autotest_private::AppReadiness:: |
| APP_READINESS_UNINSTALLEDBYMIGRATION; |
| case apps::mojom::Readiness::kUnknown: |
| return api::autotest_private::AppReadiness::APP_READINESS_NONE; |
| } |
| NOTREACHED(); |
| return api::autotest_private::AppReadiness::APP_READINESS_NONE; |
| } |
| |
| api::autotest_private::HotseatState GetHotseatState( |
| ash::HotseatState hotseat_state) { |
| switch (hotseat_state) { |
| case ash::HotseatState::kNone: |
| return api::autotest_private::HotseatState::HOTSEAT_STATE_NONE; |
| case ash::HotseatState::kHidden: |
| return api::autotest_private::HotseatState::HOTSEAT_STATE_HIDDEN; |
| case ash::HotseatState::kShownClamshell: |
| return api::autotest_private::HotseatState::HOTSEAT_STATE_SHOWNCLAMSHELL; |
| case ash::HotseatState::kShownHomeLauncher: |
| return api::autotest_private::HotseatState:: |
| HOTSEAT_STATE_SHOWNHOMELAUNCHER; |
| case ash::HotseatState::kExtended: |
| return api::autotest_private::HotseatState::HOTSEAT_STATE_EXTENDED; |
| } |
| |
| NOTREACHED(); |
| } |
| |
| std::unique_ptr<bool> ConvertMojomOptionalBool( |
| apps::mojom::OptionalBool optional) { |
| switch (optional) { |
| case apps::mojom::OptionalBool::kTrue: |
| return std::make_unique<bool>(true); |
| case apps::mojom::OptionalBool::kFalse: |
| return std::make_unique<bool>(false); |
| case apps::mojom::OptionalBool::kUnknown: |
| return nullptr; |
| } |
| NOTREACHED(); |
| return nullptr; |
| } |
| |
| // Helper function to set whitelisted user pref based on |pref_name| with any |
| // specific pref validations. Returns error messages if any. |
| std::string SetWhitelistedPref(Profile* profile, |
| const std::string& pref_name, |
| const base::Value& value) { |
| // Special case for the preference that is stored in the "Local State" |
| // profile. |
| if (pref_name == prefs::kEnableAdbSideloadingRequested) { |
| DCHECK(value.is_bool()); |
| g_browser_process->local_state()->Set(pref_name, value); |
| return std::string(); |
| } |
| |
| if (pref_name == chromeos::assistant::prefs::kAssistantEnabled) { |
| if (!value.is_bool()) |
| return "Invalid value type."; |
| // Validate the Assistant service allowed state. |
| chromeos::assistant::AssistantAllowedState allowed_state = |
| assistant::IsAssistantAllowedForProfile(profile); |
| if (allowed_state != chromeos::assistant::AssistantAllowedState::ALLOWED) { |
| return base::StringPrintf("Assistant not allowed - state: %d", |
| allowed_state); |
| } |
| } else if (pref_name == chromeos::assistant::prefs::kAssistantConsentStatus) { |
| if (!value.is_int()) |
| return "Invalid value type."; |
| if (!profile->GetPrefs()->GetBoolean( |
| chromeos::assistant::prefs::kAssistantEnabled)) { |
| return "Unable to set the pref because Assistant has not been enabled."; |
| } |
| } else if (pref_name == |
| chromeos::assistant::prefs::kAssistantContextEnabled || |
| pref_name == |
| chromeos::assistant::prefs::kAssistantHotwordEnabled) { |
| if (!value.is_bool()) |
| return "Invalid value type."; |
| // Assistant service must be enabled first for those prefs to take effect. |
| if (!profile->GetPrefs()->GetBoolean( |
| chromeos::assistant::prefs::kAssistantEnabled)) { |
| return std::string( |
| "Unable to set the pref because Assistant has not been enabled."); |
| } |
| } else if (pref_name == |
| ash::prefs::kAssistantNumSessionsWhereOnboardingShown) { |
| if (!value.is_int()) |
| return "Invalid value type."; |
| } else if (pref_name == ash::prefs::kAccessibilityVirtualKeyboardEnabled) { |
| DCHECK(value.is_bool()); |
| } else if (pref_name == prefs::kLanguagePreloadEngines) { |
| DCHECK(value.is_string()); |
| } else if (pref_name == plugin_vm::prefs::kPluginVmCameraAllowed) { |
| DCHECK(value.is_bool()); |
| } else if (pref_name == plugin_vm::prefs::kPluginVmMicAllowed) { |
| DCHECK(value.is_bool()); |
| } else { |
| return "The pref " + pref_name + " is not whitelisted."; |
| } |
| |
| // Set value for the specified user pref after validation. |
| profile->GetPrefs()->Set(pref_name, value); |
| |
| return std::string(); |
| } |
| |
| // Returns the ARC app window that associates with |package_name|. Note there |
| // might be more than 1 windows that have the same package name. This function |
| // just returns the first window it finds. |
| aura::Window* GetArcAppWindow(const std::string& package_name) { |
| for (auto* window : ChromeShelfController::instance()->GetArcWindows()) { |
| std::string* pkg_name = window->GetProperty(ash::kArcPackageNameKey); |
| if (pkg_name && *pkg_name == package_name) |
| return window; |
| } |
| return nullptr; |
| } |
| |
| // Gets expected window state type according to |event_type|. |
| chromeos::WindowStateType GetExpectedWindowState( |
| api::autotest_private::WMEventType event_type) { |
| switch (event_type) { |
| case api::autotest_private::WMEventType::WM_EVENT_TYPE_WMEVENTNORMAL: |
| return chromeos::WindowStateType::kNormal; |
| case api::autotest_private::WMEventType::WM_EVENT_TYPE_WMEVENTMAXIMIZE: |
| return chromeos::WindowStateType::kMaximized; |
| case api::autotest_private::WMEventType::WM_EVENT_TYPE_WMEVENTMINIMIZE: |
| return chromeos::WindowStateType::kMinimized; |
| case api::autotest_private::WMEventType::WM_EVENT_TYPE_WMEVENTFULLSCREEN: |
| return chromeos::WindowStateType::kFullscreen; |
| case api::autotest_private::WMEventType::WM_EVENT_TYPE_WMEVENTSNAPLEFT: |
| return chromeos::WindowStateType::kPrimarySnapped; |
| case api::autotest_private::WMEventType::WM_EVENT_TYPE_WMEVENTSNAPRIGHT: |
| return chromeos::WindowStateType::kSecondarySnapped; |
| default: |
| NOTREACHED(); |
| return chromeos::WindowStateType::kNormal; |
| } |
| } |
| |
| ash::WMEventType ToWMEventType(api::autotest_private::WMEventType event_type) { |
| switch (event_type) { |
| case api::autotest_private::WMEventType::WM_EVENT_TYPE_WMEVENTNORMAL: |
| return ash::WMEventType::WM_EVENT_NORMAL; |
| case api::autotest_private::WMEventType::WM_EVENT_TYPE_WMEVENTMAXIMIZE: |
| return ash::WMEventType::WM_EVENT_MAXIMIZE; |
| case api::autotest_private::WMEventType::WM_EVENT_TYPE_WMEVENTMINIMIZE: |
| return ash::WMEventType::WM_EVENT_MINIMIZE; |
| case api::autotest_private::WMEventType::WM_EVENT_TYPE_WMEVENTFULLSCREEN: |
| return ash::WMEventType::WM_EVENT_FULLSCREEN; |
| case api::autotest_private::WMEventType::WM_EVENT_TYPE_WMEVENTSNAPLEFT: |
| return ash::WMEventType::WM_EVENT_SNAP_PRIMARY; |
| case api::autotest_private::WMEventType::WM_EVENT_TYPE_WMEVENTSNAPRIGHT: |
| return ash::WMEventType::WM_EVENT_SNAP_SECONDARY; |
| default: |
| NOTREACHED(); |
| return ash::WMEventType::WM_EVENT_NORMAL; |
| } |
| } |
| |
| api::autotest_private::WindowStateType ToWindowStateType( |
| chromeos::WindowStateType state_type) { |
| switch (state_type) { |
| // Consider adding DEFAULT type to idl. |
| case chromeos::WindowStateType::kDefault: |
| case chromeos::WindowStateType::kNormal: |
| return api::autotest_private::WindowStateType::WINDOW_STATE_TYPE_NORMAL; |
| case chromeos::WindowStateType::kMinimized: |
| return api::autotest_private::WindowStateType:: |
| WINDOW_STATE_TYPE_MINIMIZED; |
| case chromeos::WindowStateType::kMaximized: |
| return api::autotest_private::WindowStateType:: |
| WINDOW_STATE_TYPE_MAXIMIZED; |
| case chromeos::WindowStateType::kFullscreen: |
| return api::autotest_private::WindowStateType:: |
| WINDOW_STATE_TYPE_FULLSCREEN; |
| case chromeos::WindowStateType::kPrimarySnapped: |
| return api::autotest_private::WindowStateType:: |
| WINDOW_STATE_TYPE_LEFTSNAPPED; |
| case chromeos::WindowStateType::kSecondarySnapped: |
| return api::autotest_private::WindowStateType:: |
| WINDOW_STATE_TYPE_RIGHTSNAPPED; |
| case chromeos::WindowStateType::kPip: |
| return api::autotest_private::WindowStateType::WINDOW_STATE_TYPE_PIP; |
| default: |
| NOTREACHED(); |
| return api::autotest_private::WindowStateType::WINDOW_STATE_TYPE_NONE; |
| } |
| } |
| |
| std::string GetPngDataAsString(scoped_refptr<base::RefCountedMemory> png_data) { |
| // Base64 encode the result so we can return it as a string. |
| std::string base64Png(png_data->front(), |
| png_data->front() + png_data->size()); |
| base::Base64Encode(base64Png, &base64Png); |
| return base64Png; |
| } |
| |
| display::Display::Rotation ToRotation( |
| api::autotest_private::RotationType rotation) { |
| switch (rotation) { |
| case api::autotest_private::RotationType::ROTATION_TYPE_ROTATE0: |
| return display::Display::ROTATE_0; |
| case api::autotest_private::RotationType::ROTATION_TYPE_ROTATE90: |
| return display::Display::ROTATE_90; |
| case api::autotest_private::RotationType::ROTATION_TYPE_ROTATE180: |
| return display::Display::ROTATE_180; |
| case api::autotest_private::RotationType::ROTATION_TYPE_ROTATE270: |
| return display::Display::ROTATE_270; |
| case api::autotest_private::RotationType::ROTATION_TYPE_ROTATEANY: |
| case api::autotest_private::RotationType::ROTATION_TYPE_NONE: |
| break; |
| } |
| NOTREACHED(); |
| return display::Display::ROTATE_0; |
| } |
| |
| api::autotest_private::Bounds ToBoundsDictionary(const gfx::Rect& bounds) { |
| api::autotest_private::Bounds result; |
| result.left = bounds.x(); |
| result.top = bounds.y(); |
| result.width = bounds.width(); |
| result.height = bounds.height(); |
| return result; |
| } |
| |
| gfx::Rect ToRect(const api::autotest_private::Bounds& result) { |
| return gfx::Rect(result.left, result.top, result.width, result.height); |
| } |
| |
| std::vector<api::autotest_private::Bounds> ToBoundsDictionaryList( |
| const std::vector<gfx::Rect>& items_bounds) { |
| std::vector<api::autotest_private::Bounds> bounds_list; |
| for (const gfx::Rect& bounds : items_bounds) |
| bounds_list.push_back(ToBoundsDictionary(bounds)); |
| return bounds_list; |
| } |
| |
| api::autotest_private::Location ToLocationDictionary(const gfx::Point& point) { |
| api::autotest_private::Location result; |
| result.x = point.x(); |
| result.y = point.y(); |
| return result; |
| } |
| |
| aura::Window* FindAppWindowById(const int64_t id) { |
| auto list = ash::GetAppWindowList(); |
| auto iter = std::find_if( |
| list.begin(), list.end(), |
| [id](aura::Window* window) { return window->GetId() == id; }); |
| if (iter == list.end()) |
| return nullptr; |
| return *iter; |
| } |
| |
| // Returns the first available Browser that is not a web app. |
| Browser* GetFirstRegularBrowser() { |
| const BrowserList* list = BrowserList::GetInstance(); |
| auto iter = std::find_if(list->begin(), list->end(), [](Browser* browser) { |
| return browser->app_controller() == nullptr; |
| }); |
| if (iter == list->end()) |
| return nullptr; |
| return *iter; |
| } |
| |
| ash::AppListViewState ToAppListViewState( |
| api::autotest_private::LauncherStateType state) { |
| switch (state) { |
| case api::autotest_private::LauncherStateType::LAUNCHER_STATE_TYPE_CLOSED: |
| return ash::AppListViewState::kClosed; |
| case api::autotest_private::LauncherStateType::LAUNCHER_STATE_TYPE_PEEKING: |
| return ash::AppListViewState::kPeeking; |
| case api::autotest_private::LauncherStateType::LAUNCHER_STATE_TYPE_HALF: |
| return ash::AppListViewState::kHalf; |
| case api::autotest_private::LauncherStateType:: |
| LAUNCHER_STATE_TYPE_FULLSCREENALLAPPS: |
| return ash::AppListViewState::kFullscreenAllApps; |
| case api::autotest_private::LauncherStateType:: |
| LAUNCHER_STATE_TYPE_FULLSCREENSEARCH: |
| return ash::AppListViewState::kFullscreenSearch; |
| case api::autotest_private::LauncherStateType::LAUNCHER_STATE_TYPE_NONE: |
| break; |
| } |
| return ash::AppListViewState::kClosed; |
| } |
| |
| ash::OverviewAnimationState ToOverviewAnimationState( |
| api::autotest_private::OverviewStateType state) { |
| switch (state) { |
| case api::autotest_private::OverviewStateType::OVERVIEW_STATE_TYPE_SHOWN: |
| return ash::OverviewAnimationState::kEnterAnimationComplete; |
| case api::autotest_private::OverviewStateType::OVERVIEW_STATE_TYPE_HIDDEN: |
| return ash::OverviewAnimationState::kExitAnimationComplete; |
| case api::autotest_private::OverviewStateType::OVERVIEW_STATE_TYPE_NONE: |
| break; |
| } |
| NOTREACHED(); |
| return ash::OverviewAnimationState::kExitAnimationComplete; |
| } |
| |
| ui::KeyboardCode StringToKeyCode(const std::string& str) { |
| constexpr struct Map { |
| const char* str; |
| ui::KeyboardCode key_code; |
| } map[] = { |
| {"search", ui::VKEY_LWIN}, |
| {"assistant", ui::VKEY_ASSISTANT}, |
| }; |
| DCHECK(base::IsStringASCII(str)); |
| if (str.length() == 1) { |
| char c = str[0]; |
| if (c >= 'a' && c <= 'z') { |
| return static_cast<ui::KeyboardCode>(static_cast<int>(ui::VKEY_A) + |
| (c - 'a')); |
| } |
| if (c >= '0' && c <= '9') { |
| return static_cast<ui::KeyboardCode>(static_cast<int>(ui::VKEY_0) + |
| (c - '0')); |
| } |
| } else { |
| for (auto& entry : map) { |
| if (str == entry.str) |
| return entry.key_code; |
| } |
| } |
| NOTREACHED(); |
| return ui::VKEY_A; |
| } |
| |
| aura::Window* GetActiveWindow() { |
| std::vector<aura::Window*> list = ash::GetAppWindowList(); |
| if (!list.size()) |
| return nullptr; |
| return wm::GetActivationClient(list[0]->GetRootWindow())->GetActiveWindow(); |
| } |
| |
| bool IsFrameVisible(views::Widget* widget) { |
| views::NonClientFrameView* frame_view = |
| widget->non_client_view() ? widget->non_client_view()->frame_view() |
| : nullptr; |
| return frame_view && frame_view->GetEnabled() && frame_view->GetVisible(); |
| } |
| |
| void ConvertPointToHost(aura::Window* root_window, gfx::PointF* location) { |
| gfx::Point3F transformed_location_in_root(*location); |
| root_window->GetHost()->GetRootTransform().TransformPoint( |
| &transformed_location_in_root); |
| *location = transformed_location_in_root.AsPointF(); |
| } |
| |
| int GetMouseEventFlags(api::autotest_private::MouseButton button) { |
| switch (button) { |
| case api::autotest_private::MOUSE_BUTTON_LEFT: |
| return ui::EF_LEFT_MOUSE_BUTTON; |
| case api::autotest_private::MOUSE_BUTTON_RIGHT: |
| return ui::EF_RIGHT_MOUSE_BUTTON; |
| case api::autotest_private::MOUSE_BUTTON_MIDDLE: |
| return ui::EF_MIDDLE_MOUSE_BUTTON; |
| default: |
| NOTREACHED(); |
| } |
| return ui::EF_NONE; |
| } |
| |
| // Gets display id out of an optional DOMString display id argument. Returns |
| // false if optional display id is given but in bad format. Otherwise returns |
| // true and fills |display_id| with either the primary display id when the |
| // optional arg is not given or the parsed display id out of the arg |
| bool GetDisplayIdFromOptionalArg(const std::unique_ptr<std::string>& arg, |
| int64_t* display_id) { |
| if (arg.get() && !arg->empty()) { |
| return base::StringToInt64(*arg, display_id); |
| } |
| |
| *display_id = display::Screen::GetScreen()->GetPrimaryDisplay().id(); |
| return true; |
| } |
| |
| struct SmoothnessTrackerInfo { |
| absl::optional<ui::ThroughputTracker> tracker; |
| ui::ThroughputTrackerHost::ReportCallback callback; |
| }; |
| using DisplaySmoothnessTrackerInfos = std::map<int64_t, SmoothnessTrackerInfo>; |
| DisplaySmoothnessTrackerInfos* GetDisplaySmoothnessTrackerInfos() { |
| static base::NoDestructor<DisplaySmoothnessTrackerInfos> trackers; |
| return trackers.get(); |
| } |
| |
| // Forwards frame rate data to the callback for |display_id| and resets. |
| void ForwardFrameRateDataAndReset( |
| int64_t display_id, |
| const cc::FrameSequenceMetrics::CustomReportData& data) { |
| auto* infos = GetDisplaySmoothnessTrackerInfos(); |
| auto it = infos->find(display_id); |
| DCHECK(it != infos->end()); |
| DCHECK(it->second.callback); |
| |
| // Moves the callback out and erases the mapping first to allow new tracking |
| // for |display_id| to start before |callback| run returns. |
| // See https://crbug.com/1098886. |
| auto callback = std::move(it->second.callback); |
| infos->erase(it); |
| std::move(callback).Run(data); |
| } |
| |
| std::string ResolutionToString( |
| chromeos::assistant::AssistantInteractionResolution resolution) { |
| using chromeos::assistant::AssistantInteractionResolution; |
| switch (resolution) { |
| case AssistantInteractionResolution::kNormal: |
| return "kNormal"; |
| case AssistantInteractionResolution::kError: |
| return "kError"; |
| case AssistantInteractionResolution::kInterruption: |
| return "kInterruption"; |
| case AssistantInteractionResolution::kMicTimeout: |
| return "kMicTimeout"; |
| case AssistantInteractionResolution::kMultiDeviceHotwordLoss: |
| return "kMultiDeviceHotwordLoss"; |
| } |
| |
| // Not reachable here. |
| DCHECK(false); |
| } |
| |
| } // namespace |
| |
| class WindowStateChangeObserver : public aura::WindowObserver { |
| public: |
| WindowStateChangeObserver(aura::Window* window, |
| chromeos::WindowStateType expected_type, |
| base::OnceCallback<void(bool)> callback) |
| : expected_type_(expected_type), callback_(std::move(callback)) { |
| DCHECK_NE(window->GetProperty(chromeos::kWindowStateTypeKey), |
| expected_type_); |
| scoped_observation_.Observe(window); |
| } |
| ~WindowStateChangeObserver() override {} |
| |
| // aura::WindowObserver: |
| void OnWindowPropertyChanged(aura::Window* window, |
| const void* key, |
| intptr_t old) override { |
| DCHECK(scoped_observation_.IsObservingSource(window)); |
| if (key == chromeos::kWindowStateTypeKey && |
| window->GetProperty(chromeos::kWindowStateTypeKey) == expected_type_) { |
| scoped_observation_.Reset(); |
| std::move(callback_).Run(/*success=*/true); |
| } |
| } |
| |
| void OnWindowDestroying(aura::Window* window) override { |
| DCHECK(scoped_observation_.IsObservingSource(window)); |
| scoped_observation_.Reset(); |
| std::move(callback_).Run(/*success=*/false); |
| } |
| |
| private: |
| chromeos::WindowStateType expected_type_; |
| base::ScopedObservation<aura::Window, aura::WindowObserver> |
| scoped_observation_{this}; |
| base::OnceCallback<void(bool)> callback_; |
| |
| DISALLOW_COPY_AND_ASSIGN(WindowStateChangeObserver); |
| }; |
| |
| class WindowBoundsChangeObserver : public aura::WindowObserver { |
| public: |
| WindowBoundsChangeObserver( |
| aura::Window* window, |
| const gfx::Rect& to_bounds, |
| int64_t display_id, |
| base::OnceCallback<void(const gfx::Rect&, int64_t, bool)> callback) |
| : callback_(std::move(callback)) { |
| auto* state = ash::WindowState::Get(window); |
| DCHECK(state); |
| wait_for_bounds_change_ = window->GetBoundsInRootWindow() != to_bounds; |
| wait_for_display_change_ = state->GetDisplay().id() != display_id; |
| DCHECK(wait_for_bounds_change_ || wait_for_display_change_); |
| scoped_observation_.Observe(window); |
| } |
| ~WindowBoundsChangeObserver() override = default; |
| |
| WindowBoundsChangeObserver(const WindowBoundsChangeObserver&) = delete; |
| WindowBoundsChangeObserver& operator=(const WindowBoundsChangeObserver&) = |
| delete; |
| |
| // aura::WindowObserver: |
| void OnWindowBoundsChanged(aura::Window* window, |
| const gfx::Rect& old_bounds, |
| const gfx::Rect& new_bounds, |
| ui::PropertyChangeReason reason) override { |
| wait_for_bounds_change_ = false; |
| MaybeFinishObserving(window, /*success=*/true); |
| } |
| |
| void OnWindowAddedToRootWindow(aura::Window* window) override { |
| wait_for_display_change_ = false; |
| MaybeFinishObserving(window, /*success=*/true); |
| } |
| |
| void OnWindowDestroying(aura::Window* window) override { |
| wait_for_display_change_ = false; |
| wait_for_bounds_change_ = false; |
| MaybeFinishObserving(window, /*success=*/false); |
| } |
| |
| private: |
| void MaybeFinishObserving(aura::Window* window, bool success) { |
| DCHECK(scoped_observation_.IsObservingSource(window)); |
| if (!wait_for_bounds_change_ && !wait_for_display_change_) { |
| scoped_observation_.Reset(); |
| std::move(callback_).Run(window->GetBoundsInRootWindow(), |
| ash::WindowState::Get(window)->GetDisplay().id(), |
| success); |
| } |
| } |
| |
| base::ScopedObservation<aura::Window, aura::WindowObserver> |
| scoped_observation_{this}; |
| bool wait_for_bounds_change_ = false; |
| bool wait_for_display_change_ = false; |
| base::OnceCallback<void(const gfx::Rect&, int64_t, bool)> callback_; |
| }; |
| |
| class EventGenerator { |
| public: |
| EventGenerator(aura::WindowTreeHost* host, base::OnceClosure closure) |
| : input_injector_( |
| ui::OzonePlatform::GetInstance()->CreateSystemInputInjector()), |
| host_(host), |
| interval_(base::TimeDelta::FromSeconds(1) / |
| std::max(host->compositor()->refresh_rate(), 60.0f)), |
| closure_(std::move(closure)), |
| weak_ptr_factory_(this) { |
| LOG_IF(ERROR, host->compositor()->refresh_rate() < 60.0f) |
| << "Refresh rate (" << host->compositor()->refresh_rate() |
| << ") is too low."; |
| } |
| ~EventGenerator() = default; |
| |
| void ScheduleMouseEvent(ui::EventType type, |
| gfx::PointF location_in_screen, |
| int flags) { |
| if (flags == 0 && |
| (type == ui::ET_MOUSE_PRESSED || type == ui::ET_MOUSE_RELEASED)) { |
| LOG(ERROR) << "No flags specified for mouse button changes"; |
| } |
| tasks_.push_back(Task(type, location_in_screen, flags)); |
| } |
| |
| void Run() { |
| next_event_timestamp_ = base::TimeTicks::Now(); |
| SendEvent(); |
| } |
| |
| const base::TimeDelta& interval() const { return interval_; } |
| |
| private: |
| struct Task { |
| enum Status { |
| kNotScheduled, |
| kScheduled, |
| }; |
| |
| const ui::EventType type; |
| const gfx::PointF location_in_screen; |
| const int flags; |
| Status status = kNotScheduled; |
| |
| Task(ui::EventType type, gfx::PointF location_in_screen, int flags) |
| : type(type), location_in_screen(location_in_screen), flags(flags) {} |
| }; |
| |
| void SendEvent() { |
| if (tasks_.empty()) { |
| std::move(closure_).Run(); |
| return; |
| } |
| Task* task = &tasks_.front(); |
| DCHECK_EQ(task->status, Task::kNotScheduled); |
| // A task can be processed asynchronously; the next task will be scheduled |
| // after the control returns to the message pump, assuming that implies the |
| // processing of the current task has finished. |
| // WindowEventDispatcherObserver was used but the way it works does not |
| // support nested loop in window move/resize or drag-n-drop. In such |
| // cases, the mouse move event triggers the nested loop does not finish |
| // until the nested loop quits. But this blocks future mouse events. Hence |
| // the operation does not finish and the nested loop does not quit. |
| task->status = Task::kScheduled; |
| switch (task->type) { |
| case ui::ET_MOUSE_PRESSED: |
| case ui::ET_MOUSE_RELEASED: { |
| bool pressed = (task->type == ui::ET_MOUSE_PRESSED); |
| if (task->flags & ui::EF_LEFT_MOUSE_BUTTON) |
| input_injector_->InjectMouseButton(ui::EF_LEFT_MOUSE_BUTTON, pressed); |
| if (task->flags & ui::EF_MIDDLE_MOUSE_BUTTON) { |
| input_injector_->InjectMouseButton(ui::EF_MIDDLE_MOUSE_BUTTON, |
| pressed); |
| } |
| if (task->flags & ui::EF_RIGHT_MOUSE_BUTTON) { |
| input_injector_->InjectMouseButton(ui::EF_RIGHT_MOUSE_BUTTON, |
| pressed); |
| } |
| break; |
| } |
| case ui::ET_MOUSE_MOVED: { |
| display::Display display = |
| display::Screen::GetScreen()->GetDisplayNearestPoint( |
| gfx::ToFlooredPoint((task->location_in_screen))); |
| auto* root_window = ash::Shell::GetRootWindowForDisplayId(display.id()); |
| if (!root_window->GetBoundsInScreen().Contains( |
| gfx::ToFlooredPoint(task->location_in_screen))) { |
| // Not in any of the display. Does nothing and schedules a new task. |
| OnFinishedProcessingEvent(); |
| return; |
| } |
| gfx::PointF location_in_host(task->location_in_screen); |
| wm::ConvertPointFromScreen(root_window, &location_in_host); |
| ConvertPointToHost(root_window, &location_in_host); |
| if (root_window->GetHost() != host_) { |
| // Switching to the new display. |
| host_ = root_window->GetHost(); |
| host_->MoveCursorToLocationInPixels( |
| gfx::ToFlooredPoint(location_in_host)); |
| } |
| // The location should be offset by the origin of the root-window since |
| // ui::SystemInputInjector expects so. |
| input_injector_->MoveCursorTo( |
| location_in_host + host_->GetBoundsInPixels().OffsetFromOrigin()); |
| break; |
| } |
| default: |
| NOTREACHED(); |
| } |
| |
| // Post a task after scheduling the event and assumes that when the task |
| // runs, it implies that the processing of the scheduled event is finished. |
| base::SequencedTaskRunnerHandle::Get()->PostTask( |
| FROM_HERE, base::BindOnce(&EventGenerator::OnFinishedProcessingEvent, |
| weak_ptr_factory_.GetWeakPtr())); |
| } |
| |
| void OnFinishedProcessingEvent() { |
| if (tasks_.empty()) |
| return; |
| |
| DCHECK_EQ(tasks_.front().status, Task::kScheduled); |
| tasks_.pop_front(); |
| auto runner = base::SequencedTaskRunnerHandle::Get(); |
| auto closure = base::BindOnce(&EventGenerator::SendEvent, |
| weak_ptr_factory_.GetWeakPtr()); |
| // Non moving tasks can be done immediately. |
| if (tasks_.empty() || tasks_.front().type == ui::ET_MOUSE_PRESSED || |
| tasks_.front().type == ui::ET_MOUSE_RELEASED) { |
| runner->PostTask(FROM_HERE, std::move(closure)); |
| return; |
| } |
| next_event_timestamp_ += interval_; |
| auto now = base::TimeTicks::Now(); |
| base::TimeDelta interval = next_event_timestamp_ - now; |
| if (interval <= base::TimeDelta()) { |
| // Looks like event handling could take too long time -- still generate |
| // the next event with resetting the interval. |
| LOG(ERROR) << "The handling of the event spent long time and there is " |
| << "no time to delay. The next event is supposed to happen at " |
| << next_event_timestamp_ << " but now at " << now << ". " |
| << "Posting the next event immediately."; |
| next_event_timestamp_ = now; |
| runner->PostTask(FROM_HERE, std::move(closure)); |
| } else { |
| runner->PostDelayedTask(FROM_HERE, std::move(closure), interval); |
| } |
| } |
| |
| std::unique_ptr<ui::SystemInputInjector> input_injector_; |
| aura::WindowTreeHost* host_; |
| base::TimeTicks next_event_timestamp_; |
| const base::TimeDelta interval_; |
| base::OnceClosure closure_; |
| std::deque<Task> tasks_; |
| |
| base::WeakPtrFactory<EventGenerator> weak_ptr_factory_; |
| }; |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateInitializeEventsFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateInitializeEventsFunction:: |
| ~AutotestPrivateInitializeEventsFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| AutotestPrivateInitializeEventsFunction::Run() { |
| // AutotestPrivateAPI is lazily initialized, but needs to be created before |
| // any of its events can be fired, so we get the instance here and return. |
| AutotestPrivateAPI::GetFactoryInstance()->Get(browser_context()); |
| return RespondNow(NoArguments()); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateLogoutFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateLogoutFunction::~AutotestPrivateLogoutFunction() = default; |
| |
| ExtensionFunction::ResponseAction AutotestPrivateLogoutFunction::Run() { |
| DVLOG(1) << "AutotestPrivateLogoutFunction"; |
| if (!IsTestMode(browser_context())) |
| chrome::AttemptUserExit(); |
| return RespondNow(NoArguments()); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateRestartFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateRestartFunction::~AutotestPrivateRestartFunction() = default; |
| |
| ExtensionFunction::ResponseAction AutotestPrivateRestartFunction::Run() { |
| DVLOG(1) << "AutotestPrivateRestartFunction"; |
| if (!IsTestMode(browser_context())) |
| chrome::AttemptRestart(); |
| return RespondNow(NoArguments()); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateShutdownFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateShutdownFunction::~AutotestPrivateShutdownFunction() = default; |
| |
| ExtensionFunction::ResponseAction AutotestPrivateShutdownFunction::Run() { |
| std::unique_ptr<api::autotest_private::Shutdown::Params> params( |
| api::autotest_private::Shutdown::Params::Create(*args_)); |
| EXTENSION_FUNCTION_VALIDATE(params.get()); |
| DVLOG(1) << "AutotestPrivateShutdownFunction " << params->force; |
| |
| if (!IsTestMode(browser_context())) |
| chrome::AttemptExit(); |
| return RespondNow(NoArguments()); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateLoginStatusFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateLoginStatusFunction::~AutotestPrivateLoginStatusFunction() = |
| default; |
| |
| ExtensionFunction::ResponseAction AutotestPrivateLoginStatusFunction::Run() { |
| DVLOG(1) << "AutotestPrivateLoginStatusFunction"; |
| auto result = std::make_unique<base::DictionaryValue>(); |
| const user_manager::UserManager* user_manager = |
| user_manager::UserManager::Get(); |
| |
| // default_screen_locker()->locked() is set when the UI is ready, so this |
| // tells us both views based lockscreen UI and screenlocker are ready. |
| const bool is_screen_locked = |
| !!chromeos::ScreenLocker::default_screen_locker() && |
| chromeos::ScreenLocker::default_screen_locker()->locked(); |
| |
| if (user_manager) { |
| result->SetBoolean("isLoggedIn", user_manager->IsUserLoggedIn()); |
| result->SetBoolean("isOwner", user_manager->IsCurrentUserOwner()); |
| result->SetBoolean("isScreenLocked", is_screen_locked); |
| result->SetBoolean("isReadyForPassword", |
| ash::LoginScreen::Get()->IsReadyForPassword()); |
| if (user_manager->IsUserLoggedIn()) { |
| result->SetBoolean("isRegularUser", |
| user_manager->IsLoggedInAsUserWithGaiaAccount()); |
| result->SetBoolean("isGuest", user_manager->IsLoggedInAsGuest()); |
| result->SetBoolean("isKiosk", user_manager->IsLoggedInAsKioskApp()); |
| |
| const user_manager::User* user = user_manager->GetActiveUser(); |
| result->SetString("email", user->GetAccountId().GetUserEmail()); |
| result->SetString("displayEmail", user->display_email()); |
| |
| std::string user_image; |
| switch (user->image_index()) { |
| case user_manager::User::USER_IMAGE_EXTERNAL: |
| user_image = "file"; |
| break; |
| |
| case user_manager::User::USER_IMAGE_PROFILE: |
| user_image = "profile"; |
| break; |
| |
| default: |
| user_image = base::NumberToString(user->image_index()); |
| break; |
| } |
| result->SetString("userImage", user_image); |
| } |
| } |
| return RespondNow( |
| OneArgument(base::Value::FromUniquePtrValue(std::move(result)))); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateLockScreenFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateLockScreenFunction::~AutotestPrivateLockScreenFunction() = |
| default; |
| |
| ExtensionFunction::ResponseAction AutotestPrivateLockScreenFunction::Run() { |
| DVLOG(1) << "AutotestPrivateLockScreenFunction"; |
| |
| chromeos::SessionManagerClient::Get()->RequestLockScreen(); |
| return RespondNow(NoArguments()); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateGetAllEnterprisePoliciesFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateGetAllEnterprisePoliciesFunction:: |
| ~AutotestPrivateGetAllEnterprisePoliciesFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| AutotestPrivateGetAllEnterprisePoliciesFunction::Run() { |
| DVLOG(1) << "AutotestPrivateGetAllEnterprisePoliciesFunction"; |
| |
| auto client = std::make_unique<policy::ChromePolicyConversionsClient>( |
| browser_context()); |
| base::Value all_policies_array = |
| policy::DictionaryPolicyConversions(std::move(client)) |
| .EnableDeviceLocalAccountPolicies(true) |
| .EnableDeviceInfo(true) |
| .ToValue(); |
| |
| return RespondNow(OneArgument(std::move(all_policies_array))); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateRefreshEnterprisePoliciesFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateRefreshEnterprisePoliciesFunction:: |
| ~AutotestPrivateRefreshEnterprisePoliciesFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| AutotestPrivateRefreshEnterprisePoliciesFunction::Run() { |
| DVLOG(1) << "AutotestPrivateRefreshEnterprisePoliciesFunction"; |
| |
| g_browser_process->policy_service()->RefreshPolicies(base::BindOnce( |
| &AutotestPrivateRefreshEnterprisePoliciesFunction::RefreshDone, this)); |
| return RespondLater(); |
| } |
| |
| void AutotestPrivateRefreshEnterprisePoliciesFunction::RefreshDone() { |
| Respond(NoArguments()); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateGetExtensionsInfoFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateGetExtensionsInfoFunction:: |
| ~AutotestPrivateGetExtensionsInfoFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| AutotestPrivateGetExtensionsInfoFunction::Run() { |
| DVLOG(1) << "AutotestPrivateGetExtensionsInfoFunction"; |
| |
| ExtensionService* service = |
| ExtensionSystem::Get(browser_context())->extension_service(); |
| ExtensionRegistry* registry = ExtensionRegistry::Get(browser_context()); |
| const ExtensionSet& extensions = registry->enabled_extensions(); |
| const ExtensionSet& disabled_extensions = registry->disabled_extensions(); |
| ExtensionActionManager* extension_action_manager = |
| ExtensionActionManager::Get(browser_context()); |
| |
| base::ListValue extensions_values; |
| ExtensionList all; |
| all.insert(all.end(), extensions.begin(), extensions.end()); |
| all.insert(all.end(), disabled_extensions.begin(), disabled_extensions.end()); |
| for (ExtensionList::const_iterator it = all.begin(); it != all.end(); ++it) { |
| const Extension* extension = it->get(); |
| std::string id = extension->id(); |
| std::unique_ptr<base::DictionaryValue> extension_value( |
| new base::DictionaryValue); |
| extension_value->SetString("id", id); |
| extension_value->SetString("version", extension->VersionString()); |
| extension_value->SetString("name", extension->name()); |
| extension_value->SetString("publicKey", extension->public_key()); |
| extension_value->SetString("description", extension->description()); |
| extension_value->SetString( |
| "backgroundUrl", BackgroundInfo::GetBackgroundURL(extension).spec()); |
| extension_value->SetString( |
| "optionsUrl", OptionsPageInfo::GetOptionsPage(extension).spec()); |
| |
| extension_value->SetKey("hostPermissions", |
| GetHostPermissions(extension, false)); |
| extension_value->SetKey("effectiveHostPermissions", |
| GetHostPermissions(extension, true)); |
| extension_value->SetKey("apiPermissions", GetAPIPermissions(extension)); |
| |
| ManifestLocation location = extension->location(); |
| extension_value->SetBoolean("isComponent", |
| location == ManifestLocation::kComponent); |
| extension_value->SetBoolean("isInternal", |
| location == ManifestLocation::kInternal); |
| extension_value->SetBoolean("isUserInstalled", |
| location == ManifestLocation::kInternal || |
| Manifest::IsUnpackedLocation(location)); |
| extension_value->SetBoolean("isEnabled", service->IsExtensionEnabled(id)); |
| extension_value->SetBoolean( |
| "allowedInIncognito", util::IsIncognitoEnabled(id, browser_context())); |
| const ExtensionAction* action = |
| extension_action_manager->GetExtensionAction(*extension); |
| extension_value->SetBoolean( |
| "hasPageAction", |
| action && action->action_type() == ActionInfo::TYPE_PAGE); |
| |
| extensions_values.Append(std::move(extension_value)); |
| } |
| |
| std::unique_ptr<base::DictionaryValue> return_value( |
| new base::DictionaryValue); |
| return_value->SetKey("extensions", std::move(extensions_values)); |
| return RespondNow( |
| OneArgument(base::Value::FromUniquePtrValue(std::move(return_value)))); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateSimulateAsanMemoryBugFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateSimulateAsanMemoryBugFunction:: |
| ~AutotestPrivateSimulateAsanMemoryBugFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| AutotestPrivateSimulateAsanMemoryBugFunction::Run() { |
| DVLOG(1) << "AutotestPrivateSimulateAsanMemoryBugFunction"; |
| |
| if (!IsTestMode(browser_context())) { |
| // This array is volatile not to let compiler optimize us out. |
| volatile int testarray[3] = {0, 0, 0}; |
| |
| // Cause Address Sanitizer to abort this process. |
| volatile int index = 5; |
| AccessArray(testarray, &index); |
| } |
| return RespondNow(NoArguments()); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateSetTouchpadSensitivityFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateSetTouchpadSensitivityFunction:: |
| ~AutotestPrivateSetTouchpadSensitivityFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| AutotestPrivateSetTouchpadSensitivityFunction::Run() { |
| std::unique_ptr<api::autotest_private::SetTouchpadSensitivity::Params> params( |
| api::autotest_private::SetTouchpadSensitivity::Params::Create(*args_)); |
| EXTENSION_FUNCTION_VALIDATE(params.get()); |
| DVLOG(1) << "AutotestPrivateSetTouchpadSensitivityFunction " << params->value; |
| |
| chromeos::system::InputDeviceSettings::Get()->SetTouchpadSensitivity( |
| params->value); |
| return RespondNow(NoArguments()); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateSetTapToClickFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateSetTapToClickFunction::~AutotestPrivateSetTapToClickFunction() = |
| default; |
| |
| ExtensionFunction::ResponseAction AutotestPrivateSetTapToClickFunction::Run() { |
| std::unique_ptr<api::autotest_private::SetTapToClick::Params> params( |
| api::autotest_private::SetTapToClick::Params::Create(*args_)); |
| EXTENSION_FUNCTION_VALIDATE(params.get()); |
| DVLOG(1) << "AutotestPrivateSetTapToClickFunction " << params->enabled; |
| |
| chromeos::system::InputDeviceSettings::Get()->SetTapToClick(params->enabled); |
| return RespondNow(NoArguments()); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateSetThreeFingerClickFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateSetThreeFingerClickFunction:: |
| ~AutotestPrivateSetThreeFingerClickFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| AutotestPrivateSetThreeFingerClickFunction::Run() { |
| std::unique_ptr<api::autotest_private::SetThreeFingerClick::Params> params( |
| api::autotest_private::SetThreeFingerClick::Params::Create(*args_)); |
| EXTENSION_FUNCTION_VALIDATE(params.get()); |
| DVLOG(1) << "AutotestPrivateSetThreeFingerClickFunction " << params->enabled; |
| |
| chromeos::system::InputDeviceSettings::Get()->SetThreeFingerClick( |
| params->enabled); |
| return RespondNow(NoArguments()); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateSetTapDraggingFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateSetTapDraggingFunction:: |
| ~AutotestPrivateSetTapDraggingFunction() = default; |
| |
| ExtensionFunction::ResponseAction AutotestPrivateSetTapDraggingFunction::Run() { |
| std::unique_ptr<api::autotest_private::SetTapDragging::Params> params( |
| api::autotest_private::SetTapDragging::Params::Create(*args_)); |
| EXTENSION_FUNCTION_VALIDATE(params.get()); |
| DVLOG(1) << "AutotestPrivateSetTapDraggingFunction " << params->enabled; |
| |
| chromeos::system::InputDeviceSettings::Get()->SetTapDragging(params->enabled); |
| return RespondNow(NoArguments()); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateSetNaturalScrollFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateSetNaturalScrollFunction:: |
| ~AutotestPrivateSetNaturalScrollFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| AutotestPrivateSetNaturalScrollFunction::Run() { |
| std::unique_ptr<api::autotest_private::SetNaturalScroll::Params> params( |
| api::autotest_private::SetNaturalScroll::Params::Create(*args_)); |
| EXTENSION_FUNCTION_VALIDATE(params.get()); |
| DVLOG(1) << "AutotestPrivateSetNaturalScrollFunction " << params->enabled; |
| |
| chromeos::system::InputDeviceSettings::Get()->SetNaturalScroll( |
| params->enabled); |
| return RespondNow(NoArguments()); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateSetMouseSensitivityFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateSetMouseSensitivityFunction:: |
| ~AutotestPrivateSetMouseSensitivityFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| AutotestPrivateSetMouseSensitivityFunction::Run() { |
| std::unique_ptr<api::autotest_private::SetMouseSensitivity::Params> params( |
| api::autotest_private::SetMouseSensitivity::Params::Create(*args_)); |
| EXTENSION_FUNCTION_VALIDATE(params.get()); |
| DVLOG(1) << "AutotestPrivateSetMouseSensitivityFunction " << params->value; |
| |
| chromeos::system::InputDeviceSettings::Get()->SetMouseSensitivity( |
| params->value); |
| return RespondNow(NoArguments()); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateSetPrimaryButtonRightFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateSetPrimaryButtonRightFunction:: |
| ~AutotestPrivateSetPrimaryButtonRightFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| AutotestPrivateSetPrimaryButtonRightFunction::Run() { |
| std::unique_ptr<api::autotest_private::SetPrimaryButtonRight::Params> params( |
| api::autotest_private::SetPrimaryButtonRight::Params::Create(*args_)); |
| EXTENSION_FUNCTION_VALIDATE(params.get()); |
| DVLOG(1) << "AutotestPrivateSetPrimaryButtonRightFunction " << params->right; |
| |
| chromeos::system::InputDeviceSettings::Get()->SetPrimaryButtonRight( |
| params->right); |
| return RespondNow(NoArguments()); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateSetMouseReverseScrollFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateSetMouseReverseScrollFunction:: |
| ~AutotestPrivateSetMouseReverseScrollFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| AutotestPrivateSetMouseReverseScrollFunction::Run() { |
| std::unique_ptr<api::autotest_private::SetMouseReverseScroll::Params> params( |
| api::autotest_private::SetMouseReverseScroll::Params::Create(*args_)); |
| EXTENSION_FUNCTION_VALIDATE(params.get()); |
| DVLOG(1) << "AutotestPrivateSetMouseReverseScrollFunction " |
| << params->enabled; |
| |
| chromeos::system::InputDeviceSettings::Get()->SetMouseReverseScroll( |
| params->enabled); |
| return RespondNow(NoArguments()); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateGetVisibleNotificationsFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateGetVisibleNotificationsFunction:: |
| AutotestPrivateGetVisibleNotificationsFunction() = default; |
| AutotestPrivateGetVisibleNotificationsFunction:: |
| ~AutotestPrivateGetVisibleNotificationsFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| AutotestPrivateGetVisibleNotificationsFunction::Run() { |
| DVLOG(1) << "AutotestPrivateGetVisibleNotificationsFunction"; |
| |
| message_center::NotificationList::Notifications notification_set = |
| message_center::MessageCenter::Get()->GetVisibleNotifications(); |
| auto values = std::make_unique<base::ListValue>(); |
| for (auto* notification : notification_set) |
| values->Append(MakeDictionaryFromNotification(*notification)); |
| return RespondNow( |
| OneArgument(base::Value::FromUniquePtrValue(std::move(values)))); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateRemoveAllNotificationsFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateRemoveAllNotificationsFunction:: |
| AutotestPrivateRemoveAllNotificationsFunction() = default; |
| AutotestPrivateRemoveAllNotificationsFunction:: |
| ~AutotestPrivateRemoveAllNotificationsFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| AutotestPrivateRemoveAllNotificationsFunction::Run() { |
| DVLOG(1) << "AutotestPrivateRemoveAllNotificationsFunction"; |
| |
| message_center::MessageCenter::Get()->RemoveAllNotifications( |
| /*by_user=*/false, message_center::MessageCenter::RemoveType::ALL); |
| return RespondNow(NoArguments()); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateGetArcStartTimeFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateGetArcStartTimeFunction:: |
| ~AutotestPrivateGetArcStartTimeFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| AutotestPrivateGetArcStartTimeFunction::Run() { |
| DVLOG(1) << "AutotestPrivateGetArcStartTimeFunction"; |
| |
| arc::ArcSessionManager* arc_session_manager = arc::ArcSessionManager::Get(); |
| if (!arc_session_manager) |
| return RespondNow(Error("Could not find ARC session manager")); |
| |
| const double start_ticks = |
| (arc_session_manager->start_time() - base::TimeTicks()).InMillisecondsF(); |
| return RespondNow(OneArgument(base::Value(start_ticks))); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateGetArcStateFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateGetArcStateFunction::~AutotestPrivateGetArcStateFunction() = |
| default; |
| |
| ExtensionFunction::ResponseAction AutotestPrivateGetArcStateFunction::Run() { |
| DVLOG(1) << "AutotestPrivateGetArcStateFunction"; |
| |
| api::autotest_private::ArcState arc_state; |
| Profile* const profile = Profile::FromBrowserContext(browser_context()); |
| |
| if (!arc::IsArcAllowedForProfile(profile)) |
| return RespondNow(Error("ARC is not available for the current user")); |
| |
| arc::ArcSessionManager* const arc_session_manager = |
| arc::ArcSessionManager::Get(); |
| if (!arc_session_manager) |
| return RespondNow(Error("Could not find ARC session manager")); |
| |
| const base::Time now_time = base::Time::Now(); |
| const base::TimeTicks now_ticks = base::TimeTicks::Now(); |
| const base::TimeTicks pre_start_time = arc_session_manager->pre_start_time(); |
| const base::TimeTicks start_time = arc_session_manager->start_time(); |
| |
| arc_state.provisioned = arc::IsArcProvisioned(profile); |
| arc_state.tos_needed = arc::IsArcTermsOfServiceNegotiationNeeded(profile); |
| arc_state.pre_start_time = |
| pre_start_time.is_null() |
| ? 0 |
| : (now_time - (now_ticks - pre_start_time)).ToJsTime(); |
| arc_state.start_time = start_time.is_null() |
| ? 0 |
| : (now_time - (now_ticks - start_time)).ToJsTime(); |
| |
| return RespondNow( |
| OneArgument(base::Value::FromUniquePtrValue(arc_state.ToValue()))); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateGetPlayStoreStateFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateGetPlayStoreStateFunction:: |
| ~AutotestPrivateGetPlayStoreStateFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| AutotestPrivateGetPlayStoreStateFunction::Run() { |
| DVLOG(1) << "AutotestPrivateGetPlayStoreStateFunction"; |
| |
| api::autotest_private::PlayStoreState play_store_state; |
| play_store_state.allowed = false; |
| Profile* profile = Profile::FromBrowserContext(browser_context()); |
| if (arc::IsArcAllowedForProfile(profile)) { |
| play_store_state.allowed = true; |
| play_store_state.enabled = |
| std::make_unique<bool>(arc::IsArcPlayStoreEnabledForProfile(profile)); |
| play_store_state.managed = std::make_unique<bool>( |
| arc::IsArcPlayStoreEnabledPreferenceManagedForProfile(profile)); |
| } |
| return RespondNow( |
| OneArgument(base::Value::FromUniquePtrValue(play_store_state.ToValue()))); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateSetPlayStoreEnabledFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateSetPlayStoreEnabledFunction:: |
| ~AutotestPrivateSetPlayStoreEnabledFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| AutotestPrivateSetPlayStoreEnabledFunction::Run() { |
| std::unique_ptr<api::autotest_private::SetPlayStoreEnabled::Params> params( |
| api::autotest_private::SetPlayStoreEnabled::Params::Create(*args_)); |
| EXTENSION_FUNCTION_VALIDATE(params); |
| DVLOG(1) << "AutotestPrivateSetPlayStoreEnabledFunction " << params->enabled; |
| |
| Profile* profile = Profile::FromBrowserContext(browser_context()); |
| if (arc::IsArcAllowedForProfile(profile)) { |
| if (!arc::SetArcPlayStoreEnabledForProfile(profile, params->enabled)) { |
| return RespondNow( |
| Error("ARC enabled state cannot be changed for the current user")); |
| } |
| // kArcLocationServiceEnabled and kArcBackupRestoreEnabled are prefs that |
| // set together with enabling ARC. That is why we set it here not using |
| // SetWhitelistedPref. At this moment, we don't distinguish the actual |
| // values and set kArcLocationServiceEnabled to true and leave |
| // kArcBackupRestoreEnabled unmodified, which is acceptable for autotests |
| // currently. |
| profile->GetPrefs()->SetBoolean(arc::prefs::kArcLocationServiceEnabled, |
| true); |
| return RespondNow(NoArguments()); |
| } else { |
| return RespondNow(Error("ARC is not available for the current user")); |
| } |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateIsAppShownFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateIsAppShownFunction::~AutotestPrivateIsAppShownFunction() = |
| default; |
| |
| ExtensionFunction::ResponseAction AutotestPrivateIsAppShownFunction::Run() { |
| std::unique_ptr<api::autotest_private::IsAppShown::Params> params( |
| api::autotest_private::IsAppShown::Params::Create(*args_)); |
| EXTENSION_FUNCTION_VALIDATE(params); |
| DVLOG(1) << "AutotestPrivateIsAppShownFunction " << params->app_id; |
| |
| ChromeShelfController* const controller = ChromeShelfController::instance(); |
| if (!controller) |
| return RespondNow(Error("Controller not available")); |
| |
| const ash::ShelfItem* item = |
| controller->GetItem(ash::ShelfID(params->app_id)); |
| // App must be running and not pending in deferred launch. |
| const bool window_attached = |
| item && item->status == ash::ShelfItemStatus::STATUS_RUNNING && |
| !controller->GetShelfSpinnerController()->HasApp(params->app_id); |
| return RespondNow(OneArgument(base::Value(window_attached))); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateIsAppShownFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateIsArcProvisionedFunction:: |
| ~AutotestPrivateIsArcProvisionedFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| AutotestPrivateIsArcProvisionedFunction::Run() { |
| DVLOG(1) << "AutotestPrivateIsArcProvisionedFunction"; |
| return RespondNow(OneArgument(base::Value( |
| arc::IsArcProvisioned(Profile::FromBrowserContext(browser_context()))))); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateGetArcPackageFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateGetArcAppFunction::~AutotestPrivateGetArcAppFunction() = default; |
| |
| ExtensionFunction::ResponseAction AutotestPrivateGetArcAppFunction::Run() { |
| std::unique_ptr<api::autotest_private::GetArcApp::Params> params( |
| api::autotest_private::GetArcApp::Params::Create(*args_)); |
| EXTENSION_FUNCTION_VALIDATE(params); |
| DVLOG(1) << "AutotestPrivateGetArcAppFunction " << params->app_id; |
| |
| ArcAppListPrefs* const prefs = |
| ArcAppListPrefs::Get(Profile::FromBrowserContext(browser_context())); |
| if (!prefs) |
| return RespondNow(Error("ARC is not available")); |
| |
| std::unique_ptr<base::DictionaryValue> app_value; |
| { |
| const std::unique_ptr<ArcAppListPrefs::AppInfo> app_info = |
| prefs->GetApp(params->app_id); |
| if (!app_info) |
| return RespondNow(Error("App is not available")); |
| |
| app_value = std::make_unique<base::DictionaryValue>(); |
| |
| app_value->SetKey("name", base::Value(std::move(app_info->name))); |
| app_value->SetKey("packageName", |
| base::Value(std::move(app_info->package_name))); |
| app_value->SetKey("activity", base::Value(std::move(app_info->activity))); |
| app_value->SetKey("intentUri", |
| base::Value(std::move(app_info->intent_uri))); |
| app_value->SetKey("iconResourceId", |
| base::Value(std::move(app_info->icon_resource_id))); |
| app_value->SetKey("lastLaunchTime", |
| base::Value(app_info->last_launch_time.ToJsTime())); |
| app_value->SetKey("installTime", |
| base::Value(app_info->install_time.ToJsTime())); |
| app_value->SetKey("sticky", base::Value(app_info->sticky)); |
| app_value->SetKey("notificationsEnabled", |
| base::Value(app_info->notifications_enabled)); |
| app_value->SetKey("ready", base::Value(app_info->ready)); |
| app_value->SetKey("suspended", base::Value(app_info->suspended)); |
| app_value->SetKey("showInLauncher", |
| base::Value(app_info->show_in_launcher)); |
| app_value->SetKey("shortcut", base::Value(app_info->shortcut)); |
| app_value->SetKey("launchable", base::Value(app_info->launchable)); |
| } |
| |
| return RespondNow( |
| OneArgument(base::Value::FromUniquePtrValue(std::move(app_value)))); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateGetArcPackageFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateGetArcPackageFunction::~AutotestPrivateGetArcPackageFunction() = |
| default; |
| |
| ExtensionFunction::ResponseAction AutotestPrivateGetArcPackageFunction::Run() { |
| std::unique_ptr<api::autotest_private::GetArcPackage::Params> params( |
| api::autotest_private::GetArcPackage::Params::Create(*args_)); |
| EXTENSION_FUNCTION_VALIDATE(params); |
| DVLOG(1) << "AutotestPrivateGetArcPackageFunction " << params->package_name; |
| |
| ArcAppListPrefs* const prefs = |
| ArcAppListPrefs::Get(Profile::FromBrowserContext(browser_context())); |
| if (!prefs) |
| return RespondNow(Error("ARC is not available")); |
| |
| std::unique_ptr<base::DictionaryValue> package_value; |
| { |
| const std::unique_ptr<ArcAppListPrefs::PackageInfo> package_info = |
| prefs->GetPackage(params->package_name); |
| if (!package_info) |
| return RespondNow(Error("Package is not available")); |
| |
| package_value = std::make_unique<base::DictionaryValue>(); |
| package_value->SetKey("packageName", |
| base::Value(std::move(package_info->package_name))); |
| package_value->SetKey("packageVersion", |
| base::Value(package_info->package_version)); |
| package_value->SetKey("lastBackupAndroidId", |
| base::Value(base::NumberToString( |
| package_info->last_backup_android_id))); |
| package_value->SetKey("lastBackupTime", |
| base::Value(base::Time::FromDeltaSinceWindowsEpoch( |
| base::TimeDelta::FromMicroseconds( |
| package_info->last_backup_time)) |
| .ToJsTime())); |
| package_value->SetKey("shouldSync", base::Value(package_info->should_sync)); |
| package_value->SetKey("system", base::Value(package_info->system)); |
| package_value->SetKey("vpnProvider", |
| base::Value(package_info->vpn_provider)); |
| } |
| return RespondNow( |
| OneArgument(base::Value::FromUniquePtrValue(std::move(package_value)))); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateWaitForSystemWebAppsInstallFunction |
| ////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateWaitForSystemWebAppsInstallFunction:: |
| AutotestPrivateWaitForSystemWebAppsInstallFunction() = default; |
| |
| AutotestPrivateWaitForSystemWebAppsInstallFunction:: |
| ~AutotestPrivateWaitForSystemWebAppsInstallFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| AutotestPrivateWaitForSystemWebAppsInstallFunction::Run() { |
| Profile* profile = Profile::FromBrowserContext(browser_context()); |
| web_app::WebAppProviderBase* provider = |
| web_app::WebAppProviderBase::GetProviderBase(profile); |
| |
| if (!provider) |
| return RespondNow(Error("Web Apps are not available for profile.")); |
| |
| provider->system_web_app_manager().on_apps_synchronized().Post( |
| FROM_HERE, |
| base::BindOnce( |
| &AutotestPrivateWaitForSystemWebAppsInstallFunction::Respond, this, |
| NoArguments())); |
| return RespondLater(); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateGetRegisteredSystemWebAppsFunction |
| ////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateGetRegisteredSystemWebAppsFunction:: |
| AutotestPrivateGetRegisteredSystemWebAppsFunction() = default; |
| |
| AutotestPrivateGetRegisteredSystemWebAppsFunction:: |
| ~AutotestPrivateGetRegisteredSystemWebAppsFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| AutotestPrivateGetRegisteredSystemWebAppsFunction::Run() { |
| Profile* profile = Profile::FromBrowserContext(browser_context()); |
| web_app::WebAppProviderBase* provider = |
| web_app::WebAppProviderBase::GetProviderBase(profile); |
| |
| if (!provider) |
| return RespondNow(Error("Web Apps are not available for profile.")); |
| |
| std::vector<api::autotest_private::SystemApp> result; |
| |
| for (const auto& type_and_info : |
| provider->system_web_app_manager().GetRegisteredSystemAppsForTesting()) { |
| api::autotest_private::SystemApp system_app; |
| web_app::SystemWebAppDelegate* delegate = type_and_info.second.get(); |
| system_app.internal_name = delegate->GetInternalName(); |
| system_app.url = delegate->GetInstallUrl().GetOrigin().spec(); |
| result.push_back(std::move(system_app)); |
| } |
| |
| return RespondNow(ArgumentList( |
| api::autotest_private::GetRegisteredSystemWebApps::Results::Create( |
| result))); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateIsSystemWebAppOpenFunction |
| ////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateIsSystemWebAppOpenFunction:: |
| AutotestPrivateIsSystemWebAppOpenFunction() = default; |
| |
| AutotestPrivateIsSystemWebAppOpenFunction:: |
| ~AutotestPrivateIsSystemWebAppOpenFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| AutotestPrivateIsSystemWebAppOpenFunction::Run() { |
| Profile* profile = Profile::FromBrowserContext(browser_context()); |
| web_app::WebAppProviderBase* provider = |
| web_app::WebAppProviderBase::GetProviderBase(profile); |
| |
| if (!provider) |
| return RespondNow(Error("Web Apps are not available for profile.")); |
| |
| std::unique_ptr<api::autotest_private::IsSystemWebAppOpen::Params> params( |
| api::autotest_private::IsSystemWebAppOpen::Params::Create(*args_)); |
| EXTENSION_FUNCTION_VALIDATE(params); |
| DVLOG(1) << "AutotestPrivateIsSystemWebAppOpenFunction " << params->app_id; |
| absl::optional<web_app::SystemAppType> app_type = |
| web_app::GetSystemWebAppTypeForAppId(profile, params->app_id); |
| if (!app_type) |
| return RespondNow(Error("No system web app is found by given app id.")); |
| |
| return RespondNow(OneArgument(base::Value( |
| web_app::FindSystemWebAppBrowser(profile, *app_type) != nullptr))); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateLaunchArcIntentFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateLaunchArcAppFunction::~AutotestPrivateLaunchArcAppFunction() = |
| default; |
| |
| ExtensionFunction::ResponseAction AutotestPrivateLaunchArcAppFunction::Run() { |
| std::unique_ptr<api::autotest_private::LaunchArcApp::Params> params( |
| api::autotest_private::LaunchArcApp::Params::Create(*args_)); |
| EXTENSION_FUNCTION_VALIDATE(params); |
| DVLOG(1) << "AutotestPrivateLaunchArcIntentFunction " << params->app_id << "/" |
| << params->intent; |
| |
| absl::optional<std::string> launch_intent; |
| if (!params->intent.empty()) |
| launch_intent = params->intent; |
| const bool result = arc::LaunchAppWithIntent( |
| Profile::FromBrowserContext(browser_context()), params->app_id, |
| launch_intent, 0 /* event_flags */, |
| arc::UserInteractionType::APP_STARTED_FROM_EXTENSION_API, |
| 0 /* display_id */); |
| return RespondNow(OneArgument(base::Value(result))); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateLaunchAppFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateLaunchAppFunction::~AutotestPrivateLaunchAppFunction() = default; |
| |
| ExtensionFunction::ResponseAction AutotestPrivateLaunchAppFunction::Run() { |
| std::unique_ptr<api::autotest_private::LaunchApp::Params> params( |
| api::autotest_private::LaunchApp::Params::Create(*args_)); |
| EXTENSION_FUNCTION_VALIDATE(params); |
| DVLOG(1) << "AutotestPrivateLaunchAppFunction " << params->app_id; |
| |
| ChromeShelfController* const controller = ChromeShelfController::instance(); |
| if (!controller) |
| return RespondNow(Error("Controller not available")); |
| controller->LaunchApp(ash::ShelfID(params->app_id), |
| ash::ShelfLaunchSource::LAUNCH_FROM_UNKNOWN, |
| 0, /* event_flags */ |
| display::Screen::GetScreen()->GetPrimaryDisplay().id()); |
| return RespondNow(NoArguments()); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateLaunchSystemWebAppFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateLaunchSystemWebAppFunction:: |
| ~AutotestPrivateLaunchSystemWebAppFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| AutotestPrivateLaunchSystemWebAppFunction::Run() { |
| std::unique_ptr<api::autotest_private::LaunchSystemWebApp::Params> params( |
| api::autotest_private::LaunchSystemWebApp::Params::Create(*args_)); |
| EXTENSION_FUNCTION_VALIDATE(params); |
| DVLOG(1) << "AutotestPrivateLaunchSystemWebAppFunction name: " |
| << params->app_name << " url: " << params->url; |
| |
| Profile* profile = Profile::FromBrowserContext(browser_context()); |
| auto* provider = web_app::WebAppProvider::Get(profile); |
| if (!provider) |
| return RespondNow(Error("Web Apps not enabled for profile.")); |
| |
| absl::optional<web_app::SystemAppType> app_type; |
| for (const auto& type_and_info : |
| provider->system_web_app_manager().GetRegisteredSystemAppsForTesting()) { |
| if (type_and_info.second->GetInternalName() == params->app_name) { |
| app_type = type_and_info.first; |
| break; |
| } |
| } |
| if (!app_type.has_value()) |
| return RespondNow(Error("No mapped system web app found")); |
| |
| web_app::SystemAppLaunchParams swa_params; |
| swa_params.url = GURL(params->url); |
| web_app::LaunchSystemWebAppAsync(profile, *app_type, swa_params); |
| |
| return RespondNow(NoArguments()); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateCloseAppFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateCloseAppFunction::~AutotestPrivateCloseAppFunction() = default; |
| |
| ExtensionFunction::ResponseAction AutotestPrivateCloseAppFunction::Run() { |
| std::unique_ptr<api::autotest_private::CloseApp::Params> params( |
| api::autotest_private::CloseApp::Params::Create(*args_)); |
| EXTENSION_FUNCTION_VALIDATE(params); |
| DVLOG(1) << "AutotestPrivateCloseAppFunction " << params->app_id; |
| |
| ChromeShelfController* const controller = ChromeShelfController::instance(); |
| if (!controller) |
| return RespondNow(Error("Controller not available")); |
| controller->Close(ash::ShelfID(params->app_id)); |
| return RespondNow(NoArguments()); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateGetClipboardTextDataFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateGetClipboardTextDataFunction:: |
| ~AutotestPrivateGetClipboardTextDataFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| AutotestPrivateGetClipboardTextDataFunction::Run() { |
| std::u16string data; |
| // This clipboard data read is initiated an extension API, then the user |
| // shouldn't see a notification if the clipboard is restricted by the rules of |
| // data leak prevention policy. |
| ui::DataTransferEndpoint data_dst = ui::DataTransferEndpoint( |
| ui::EndpointType::kDefault, /*notify_if_restricted=*/false); |
| ui::Clipboard::GetForCurrentThread()->ReadText( |
| ui::ClipboardBuffer::kCopyPaste, &data_dst, &data); |
| return RespondNow(OneArgument(base::Value(data))); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateSetClipboardTextDataFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateSetClipboardTextDataFunction:: |
| AutotestPrivateSetClipboardTextDataFunction() = default; |
| |
| AutotestPrivateSetClipboardTextDataFunction:: |
| ~AutotestPrivateSetClipboardTextDataFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| AutotestPrivateSetClipboardTextDataFunction::Run() { |
| observation_.Observe(ui::ClipboardMonitor::GetInstance()); |
| std::unique_ptr<api::autotest_private::SetClipboardTextData::Params> params( |
| api::autotest_private::SetClipboardTextData::Params::Create(*args_)); |
| EXTENSION_FUNCTION_VALIDATE(params); |
| |
| const std::u16string data = base::UTF8ToUTF16(params->data); |
| ui::ScopedClipboardWriter clipboard_writer(ui::ClipboardBuffer::kCopyPaste); |
| clipboard_writer.WriteText(data); |
| |
| return did_respond() ? AlreadyResponded() : RespondLater(); |
| } |
| |
| void AutotestPrivateSetClipboardTextDataFunction::OnClipboardDataChanged() { |
| observation_.Reset(); |
| Respond(NoArguments()); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateSetCrostiniEnabledFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateSetCrostiniEnabledFunction:: |
| ~AutotestPrivateSetCrostiniEnabledFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| AutotestPrivateSetCrostiniEnabledFunction::Run() { |
| std::unique_ptr<api::autotest_private::SetCrostiniEnabled::Params> params( |
| api::autotest_private::SetCrostiniEnabled::Params::Create(*args_)); |
| EXTENSION_FUNCTION_VALIDATE(params); |
| DVLOG(1) << "AutotestPrivateSetCrostiniEnabledFunction " << params->enabled; |
| |
| Profile* profile = Profile::FromBrowserContext(browser_context()); |
| if (!crostini::CrostiniFeatures::Get()->IsAllowedNow(profile)) |
| return RespondNow(Error(kCrostiniNotAvailableForCurrentUserError)); |
| |
| // Set the preference to indicate Crostini is enabled/disabled. |
| profile->GetPrefs()->SetBoolean(crostini::prefs::kCrostiniEnabled, |
| params->enabled); |
| // Set the flag to indicate we are in testing mode so that Chrome doesn't |
| // try to start the VM/container itself. |
| crostini::CrostiniManager* crostini_manager = |
| crostini::CrostiniManager::GetForProfile(profile); |
| crostini_manager->set_skip_restart_for_testing(); |
| return RespondNow(NoArguments()); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateRunCrostiniInstallerFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateRunCrostiniInstallerFunction:: |
| ~AutotestPrivateRunCrostiniInstallerFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| AutotestPrivateRunCrostiniInstallerFunction::Run() { |
| DVLOG(1) << "AutotestPrivateInstallCrostiniFunction"; |
| |
| Profile* profile = Profile::FromBrowserContext(browser_context()); |
| if (!crostini::CrostiniFeatures::Get()->IsAllowedNow(profile)) |
| return RespondNow(Error(kCrostiniNotAvailableForCurrentUserError)); |
| |
| // Run GUI installer which will install crostini vm / container and |
| // start terminal app on completion. After starting the installer, |
| // we call RestartCrostini and we will be put in the pending restarters |
| // queue and be notified on success/otherwise of installation. |
| chromeos::CrostiniInstallerDialog::Show( |
| profile, base::BindOnce([](chromeos::CrostiniInstallerUI* installer_ui) { |
| installer_ui->ClickInstallForTesting(); |
| })); |
| crostini::CrostiniManager::GetForProfile(profile)->RestartCrostini( |
| crostini::ContainerId::GetDefault(), |
| base::BindOnce( |
| &AutotestPrivateRunCrostiniInstallerFunction::CrostiniRestarted, |
| this)); |
| |
| return RespondLater(); |
| } |
| |
| void AutotestPrivateRunCrostiniInstallerFunction::CrostiniRestarted( |
| crostini::CrostiniResult result) { |
| if (result == crostini::CrostiniResult::SUCCESS) { |
| Respond(NoArguments()); |
| } else { |
| Respond(Error("Error installing crostini")); |
| } |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateRunCrostiniUninstallerFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateRunCrostiniUninstallerFunction:: |
| ~AutotestPrivateRunCrostiniUninstallerFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| AutotestPrivateRunCrostiniUninstallerFunction::Run() { |
| DVLOG(1) << "AutotestPrivateRunCrostiniUninstallerFunction"; |
| |
| Profile* profile = Profile::FromBrowserContext(browser_context()); |
| if (!crostini::CrostiniFeatures::Get()->IsAllowedNow(profile)) |
| return RespondNow(Error(kCrostiniNotAvailableForCurrentUserError)); |
| |
| // Run GUI uninstaller which will remove crostini vm / container. We then |
| // receive the callback with the result when that is complete. |
| crostini::CrostiniManager::GetForProfile(profile)->AddRemoveCrostiniCallback( |
| base::BindOnce( |
| &AutotestPrivateRunCrostiniUninstallerFunction::CrostiniRemoved, |
| this)); |
| CrostiniUninstallerView::Show(profile); |
| CrostiniUninstallerView::GetActiveViewForTesting()->Accept(); |
| return RespondLater(); |
| } |
| |
| void AutotestPrivateRunCrostiniUninstallerFunction::CrostiniRemoved( |
| crostini::CrostiniResult result) { |
| if (result == crostini::CrostiniResult::SUCCESS) |
| Respond(NoArguments()); |
| else |
| Respond(Error("Error uninstalling crostini")); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateExportCrostiniFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateExportCrostiniFunction:: |
| ~AutotestPrivateExportCrostiniFunction() = default; |
| |
| ExtensionFunction::ResponseAction AutotestPrivateExportCrostiniFunction::Run() { |
| std::unique_ptr<api::autotest_private::ExportCrostini::Params> params( |
| api::autotest_private::ExportCrostini::Params::Create(*args_)); |
| EXTENSION_FUNCTION_VALIDATE(params); |
| DVLOG(1) << "AutotestPrivateExportCrostiniFunction " << params->path; |
| |
| Profile* profile = Profile::FromBrowserContext(browser_context()); |
| if (!crostini::CrostiniFeatures::Get()->IsAllowedNow(profile) || |
| !crostini::CrostiniFeatures::Get()->IsExportImportUIAllowed(profile)) { |
| return RespondNow(Error(kCrostiniNotAvailableForCurrentUserError)); |
| } |
| |
| base::FilePath path(params->path); |
| if (path.ReferencesParent()) { |
| return RespondNow(Error("Invalid export path must not reference parent")); |
| } |
| |
| crostini::CrostiniExportImport::GetForProfile(profile)->ExportContainer( |
| crostini::ContainerId::GetDefault(), |
| file_manager::util::GetDownloadsFolderForProfile(profile).Append(path), |
| base::BindOnce(&AutotestPrivateExportCrostiniFunction::CrostiniExported, |
| this)); |
| |
| return RespondLater(); |
| } |
| |
| void AutotestPrivateExportCrostiniFunction::CrostiniExported( |
| crostini::CrostiniResult result) { |
| if (result == crostini::CrostiniResult::SUCCESS) { |
| Respond(NoArguments()); |
| } else { |
| Respond(Error("Error exporting crostini")); |
| } |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateImportCrostiniFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateImportCrostiniFunction:: |
| ~AutotestPrivateImportCrostiniFunction() = default; |
| |
| ExtensionFunction::ResponseAction AutotestPrivateImportCrostiniFunction::Run() { |
| std::unique_ptr<api::autotest_private::ImportCrostini::Params> params( |
| api::autotest_private::ImportCrostini::Params::Create(*args_)); |
| EXTENSION_FUNCTION_VALIDATE(params); |
| DVLOG(1) << "AutotestPrivateImportCrostiniFunction " << params->path; |
| |
| Profile* profile = Profile::FromBrowserContext(browser_context()); |
| if (!crostini::CrostiniFeatures::Get()->IsAllowedNow(profile) || |
| !crostini::CrostiniFeatures::Get()->IsExportImportUIAllowed(profile)) |
| return RespondNow(Error(kCrostiniNotAvailableForCurrentUserError)); |
| |
| base::FilePath path(params->path); |
| if (path.ReferencesParent()) { |
| return RespondNow(Error("Invalid import path must not reference parent")); |
| } |
| crostini::CrostiniExportImport::GetForProfile(profile)->ImportContainer( |
| crostini::ContainerId::GetDefault(), |
| file_manager::util::GetDownloadsFolderForProfile(profile).Append(path), |
| base::BindOnce(&AutotestPrivateImportCrostiniFunction::CrostiniImported, |
| this)); |
| |
| return RespondLater(); |
| } |
| |
| void AutotestPrivateImportCrostiniFunction::CrostiniImported( |
| crostini::CrostiniResult result) { |
| if (result == crostini::CrostiniResult::SUCCESS) { |
| Respond(NoArguments()); |
| } else { |
| Respond(Error("Error importing crostini")); |
| } |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateSetPluginVMPolicyFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateSetPluginVMPolicyFunction:: |
| ~AutotestPrivateSetPluginVMPolicyFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| AutotestPrivateSetPluginVMPolicyFunction::Run() { |
| std::unique_ptr<api::autotest_private::SetPluginVMPolicy::Params> params( |
| api::autotest_private::SetPluginVMPolicy::Params::Create(*args_)); |
| EXTENSION_FUNCTION_VALIDATE(params); |
| DVLOG(1) << "AutotestPrivateSetPluginVMPolicyFunction " << params->image_url |
| << ", " << params->image_hash << ", " << params->license_key; |
| |
| Profile* profile = Profile::FromBrowserContext(browser_context()); |
| plugin_vm::SetFakePluginVmPolicy(profile, params->image_url, |
| params->image_hash, params->license_key); |
| |
| return RespondNow(NoArguments()); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateShowPluginVMInstallerFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateShowPluginVMInstallerFunction:: |
| ~AutotestPrivateShowPluginVMInstallerFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| AutotestPrivateShowPluginVMInstallerFunction::Run() { |
| DVLOG(1) << "AutotestPrivateShowPluginVMInstallerFunction"; |
| |
| Profile* profile = Profile::FromBrowserContext(browser_context()); |
| plugin_vm::ShowPluginVmInstallerView(profile); |
| |
| return RespondNow(NoArguments()); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateInstallBorealisFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| class AutotestPrivateInstallBorealisFunction::InstallationObserver |
| : public borealis::BorealisInstaller::Observer { |
| public: |
| InstallationObserver(Profile* profile, |
| base::OnceCallback<void(bool)> completion_callback) |
| : observation_(this), |
| completion_callback_(std::move(completion_callback)) { |
| observation_.Observe( |
| &borealis::BorealisService::GetForProfile(profile)->Installer()); |
| base::SequencedTaskRunnerHandle::Get()->PostTask( |
| FROM_HERE, base::BindOnce( |
| [](Profile* profile) { |
| borealis::BorealisService::GetForProfile(profile) |
| ->Installer() |
| .Start(); |
| }, |
| profile)); |
| } |
| |
| void OnProgressUpdated(double fraction_complete) override {} |
| |
| void OnStateUpdated( |
| borealis::BorealisInstaller::InstallingState new_state) override {} |
| |
| void OnInstallationEnded(borealis::BorealisInstallResult result) override { |
| std::move(completion_callback_) |
| .Run(result == borealis::BorealisInstallResult::kSuccess); |
| } |
| |
| void OnCancelInitiated() override {} |
| |
| private: |
| base::ScopedObservation<borealis::BorealisInstaller, |
| borealis::BorealisInstaller::Observer> |
| observation_; |
| base::OnceCallback<void(bool)> completion_callback_; |
| }; |
| |
| AutotestPrivateInstallBorealisFunction:: |
| AutotestPrivateInstallBorealisFunction() = default; |
| |
| AutotestPrivateInstallBorealisFunction:: |
| ~AutotestPrivateInstallBorealisFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| AutotestPrivateInstallBorealisFunction::Run() { |
| Profile* profile = Profile::FromBrowserContext(browser_context()); |
| installation_observer_ = std::make_unique<InstallationObserver>( |
| profile, |
| base::BindOnce(&AutotestPrivateInstallBorealisFunction::Complete, this)); |
| return RespondLater(); |
| } |
| |
| void AutotestPrivateInstallBorealisFunction::Complete(bool was_successful) { |
| if (was_successful) { |
| Respond(NoArguments()); |
| } else { |
| Respond(Error("Failed to install borealis")); |
| } |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateRegisterComponentFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateRegisterComponentFunction:: |
| ~AutotestPrivateRegisterComponentFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| AutotestPrivateRegisterComponentFunction::Run() { |
| std::unique_ptr<api::autotest_private::RegisterComponent::Params> params( |
| api::autotest_private::RegisterComponent::Params::Create(*args_)); |
| EXTENSION_FUNCTION_VALIDATE(params); |
| DVLOG(1) << "AutotestPrivateRegisterComponentFunction " << params->name |
| << ", " << params->path; |
| |
| g_browser_process->platform_part() |
| ->cros_component_manager() |
| ->RegisterCompatiblePath(params->name, base::FilePath(params->path)); |
| |
| return RespondNow(NoArguments()); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateTakeScreenshotFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateTakeScreenshotFunction:: |
| ~AutotestPrivateTakeScreenshotFunction() = default; |
| |
| ExtensionFunction::ResponseAction AutotestPrivateTakeScreenshotFunction::Run() { |
| DVLOG(1) << "AutotestPrivateTakeScreenshotFunction"; |
| auto grabber = std::make_unique<ui::ScreenshotGrabber>(); |
| auto* const grabber_ptr = grabber.get(); |
| // TODO(mash): Fix for mash, http://crbug.com/557397 |
| aura::Window* primary_root = ash::Shell::GetPrimaryRootWindow(); |
| // Pass the ScreenshotGrabber to the callback so that it stays alive for the |
| // duration of the operation, it'll then get deallocated when the callback |
| // completes. |
| grabber_ptr->TakeScreenshot( |
| primary_root, primary_root->bounds(), |
| base::BindOnce(&AutotestPrivateTakeScreenshotFunction::ScreenshotTaken, |
| this, std::move(grabber))); |
| return RespondLater(); |
| } |
| |
| void AutotestPrivateTakeScreenshotFunction::ScreenshotTaken( |
| std::unique_ptr<ui::ScreenshotGrabber> grabber, |
| ui::ScreenshotResult screenshot_result, |
| scoped_refptr<base::RefCountedMemory> png_data) { |
| if (screenshot_result != ui::ScreenshotResult::SUCCESS) { |
| return Respond(Error(base::StrCat( |
| {"Error taking screenshot ", |
| base::NumberToString(static_cast<int>(screenshot_result))}))); |
| } |
| Respond(OneArgument(base::Value(GetPngDataAsString(png_data)))); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateTakeScreenshotForDisplayFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| AutotestPrivateTakeScreenshotForDisplayFunction:: |
| ~AutotestPrivateTakeScreenshotForDisplayFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| AutotestPrivateTakeScreenshotForDisplayFunction::Run() { |
| std::unique_ptr<api::autotest_private::TakeScreenshotForDisplay::Params> |
| params(api::autotest_private::TakeScreenshotForDisplay::Params::Create( |
| *args_)); |
| EXTENSION_FUNCTION_VALIDATE(params); |
| DVLOG(1) << "AutotestPrivateTakeScreenshotForDisplayFunction " |
| << params->display_id; |
| int64_t target_display_id; |
| base::StringToInt64(params->display_id, &target_display_id); |
| auto grabber = std::make_unique<ui::ScreenshotGrabber>(); |
| |
| for (auto* const window : ash::Shell::GetAllRootWindows()) { |
| const int64_t display_id = |
| display::Screen::GetScreen()->GetDisplayNearestWindow(window).id(); |
| if (display_id == target_display_id) { |
| auto* const grabber_ptr = grabber.get(); |
| grabber_ptr->TakeScreenshot( |
| window, window->bounds(), |
| base::BindOnce( |
| &AutotestPrivateTakeScreenshotForDisplayFunction::ScreenshotTaken, |
| this, std::move(grabber))); |
| return RespondLater(); |
| } |
| } |
| return RespondNow(Error(base::StrCat( |
| {"Error taking screenshot for display ", params->display_id}))); |
| } |
| |
| void AutotestPrivateTakeScreenshotForDisplayFunction::ScreenshotTaken( |
| std::unique_ptr<ui::ScreenshotGrabber> grabber, |
| ui::ScreenshotResult screenshot_result, |
| scoped_refptr<base::RefCountedMemory> png_data) { |
| if (screenshot_result != ui::ScreenshotResult::SUCCESS) { |
| return Respond(Error(base::StrCat( |
| {"Error taking screenshot ", |
| base::NumberToString(static_cast<int>(screenshot_result))}))); |
| } |
| Respond(OneArgument(base::Value(GetPngDataAsString(png_data)))); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateGetPrinterListFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateGetPrinterListFunction::AutotestPrivateGetPrinterListFunction() |
| : results_(std::make_unique<base::Value>(base::Value::Type::LIST)) {} |
| |
| AutotestPrivateGetPrinterListFunction:: |
| ~AutotestPrivateGetPrinterListFunction() { |
| DCHECK(!printers_manager_); |
| } |
| |
| ExtensionFunction::ResponseAction AutotestPrivateGetPrinterListFunction::Run() { |
| // |printers_manager_| should be created on UI thread. |
| DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| |
| DVLOG(1) << "AutotestPrivateGetPrinterListFunction"; |
| |
| Profile* profile = Profile::FromBrowserContext(browser_context()); |
| printers_manager_ = chromeos::CupsPrintersManager::Create(profile); |
| printers_manager_->AddObserver(this); |
| |
| // Set up a timer to finish waiting after 10 seconds |
| timeout_timer_.Start( |
| FROM_HERE, base::TimeDelta::FromSeconds(10), |
| base::BindOnce( |
| &AutotestPrivateGetPrinterListFunction::RespondWithTimeoutError, |
| this)); |
| |
| return RespondLater(); |
| } |
| |
| void AutotestPrivateGetPrinterListFunction::DestroyPrintersManager() { |
| // |printers_manager_| should be destroyed on UI thread. |
| DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| |
| if (!printers_manager_) |
| return; |
| |
| printers_manager_->RemoveObserver(this); |
| printers_manager_.reset(); |
| } |
| |
| void AutotestPrivateGetPrinterListFunction::RespondWithTimeoutError() { |
| DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| |
| if (did_respond()) |
| return; |
| |
| DestroyPrintersManager(); |
| Respond( |
| Error("Timeout occurred before Enterprise printers were initialized")); |
| } |
| |
| void AutotestPrivateGetPrinterListFunction::RespondWithSuccess() { |
| DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| |
| if (did_respond()) |
| return; |
| |
| timeout_timer_.AbandonAndStop(); |
| DestroyPrintersManager(); |
| Respond(OneArgument(base::Value::FromUniquePtrValue(std::move(results_)))); |
| } |
| |
| void AutotestPrivateGetPrinterListFunction::OnEnterprisePrintersInitialized() { |
| // |printers_manager_| should call this on UI thread. |
| DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| |
| constexpr PrinterClass kClassesToFetch[] = { |
| PrinterClass::kEnterprise, |
| PrinterClass::kSaved, |
| PrinterClass::kAutomatic, |
| }; |
| |
| // We are ready to get the list of printers and finish. |
| for (const auto& type : kClassesToFetch) { |
| std::vector<chromeos::Printer> printer_list = |
| printers_manager_->GetPrinters(type); |
| for (const auto& printer : printer_list) { |
| base::Value result(base::Value::Type::DICTIONARY); |
| result.SetKey("printerName", base::Value(printer.display_name())); |
| result.SetKey("printerId", base::Value(printer.id())); |
| result.SetKey("printerType", base::Value(GetPrinterType(type))); |
| results_->Append(std::move(result)); |
| } |
| } |
| // We have to respond in separate task on the same thread, because it will |
| // cause a destruction of CupsPrintersManager which needs to happen after |
| // we return and on the same thread. |
| base::ThreadTaskRunnerHandle::Get()->PostTask( |
| FROM_HERE, |
| base::BindOnce(&AutotestPrivateGetPrinterListFunction::RespondWithSuccess, |
| this)); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateUpdatePrinterFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateUpdatePrinterFunction::~AutotestPrivateUpdatePrinterFunction() = |
| default; |
| |
| ExtensionFunction::ResponseAction AutotestPrivateUpdatePrinterFunction::Run() { |
| std::unique_ptr<api::autotest_private::UpdatePrinter::Params> params( |
| api::autotest_private::UpdatePrinter::Params::Create(*args_)); |
| EXTENSION_FUNCTION_VALIDATE(params); |
| DVLOG(1) << "AutotestPrivateUpdatePrinterFunction"; |
| |
| const api::autotest_private::Printer& js_printer = params->printer; |
| chromeos::Printer printer(js_printer.printer_id ? *js_printer.printer_id |
| : ""); |
| printer.set_display_name(js_printer.printer_name); |
| if (js_printer.printer_desc) |
| printer.set_description(*js_printer.printer_desc); |
| |
| if (js_printer.printer_make_and_model) |
| printer.set_make_and_model(*js_printer.printer_make_and_model); |
| |
| if (js_printer.printer_uri) { |
| std::string message; |
| if (!printer.SetUri(*js_printer.printer_uri, &message)) { |
| LOG(ERROR) << message; |
| return RespondNow(Error("Incorrect URI: " + message)); |
| } |
| } |
| |
| if (js_printer.printer_ppd) { |
| const GURL ppd = |
| net::FilePathToFileURL(base::FilePath(*js_printer.printer_ppd)); |
| if (ppd.is_valid()) |
| printer.mutable_ppd_reference()->user_supplied_ppd_url = ppd.spec(); |
| else |
| LOG(ERROR) << "Invalid ppd path: " << *js_printer.printer_ppd; |
| } |
| auto* printers_manager = |
| chromeos::CupsPrintersManagerFactory::GetForBrowserContext( |
| browser_context()); |
| printers_manager->SavePrinter(printer); |
| return RespondNow(NoArguments()); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateRemovePrinterFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateRemovePrinterFunction::~AutotestPrivateRemovePrinterFunction() = |
| default; |
| |
| ExtensionFunction::ResponseAction AutotestPrivateRemovePrinterFunction::Run() { |
| std::unique_ptr<api::autotest_private::RemovePrinter::Params> params( |
| api::autotest_private::RemovePrinter::Params::Create(*args_)); |
| EXTENSION_FUNCTION_VALIDATE(params); |
| DVLOG(1) << "AutotestPrivateRemovePrinterFunction " << params->printer_id; |
| |
| auto* printers_manager = |
| chromeos::CupsPrintersManagerFactory::GetForBrowserContext( |
| browser_context()); |
| printers_manager->RemoveSavedPrinter(params->printer_id); |
| return RespondNow(NoArguments()); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateBootstrapMachineLearningServiceFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateBootstrapMachineLearningServiceFunction:: |
| AutotestPrivateBootstrapMachineLearningServiceFunction() = default; |
| AutotestPrivateBootstrapMachineLearningServiceFunction:: |
| ~AutotestPrivateBootstrapMachineLearningServiceFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| AutotestPrivateBootstrapMachineLearningServiceFunction::Run() { |
| DVLOG(1) << "AutotestPrivateBootstrapMachineLearningServiceFunction"; |
| |
| // Load a model. This will first bootstrap the Mojo connection to ML Service. |
| chromeos::machine_learning::ServiceConnection::GetInstance() |
| ->GetMachineLearningService() |
| .LoadBuiltinModel( |
| chromeos::machine_learning::mojom::BuiltinModelSpec::New( |
| chromeos::machine_learning::mojom::BuiltinModelId::TEST_MODEL), |
| model_.BindNewPipeAndPassReceiver(), |
| base::BindOnce( |
| &AutotestPrivateBootstrapMachineLearningServiceFunction:: |
| ModelLoaded, |
| this)); |
| model_.set_disconnect_handler(base::BindOnce( |
| &AutotestPrivateBootstrapMachineLearningServiceFunction::OnMojoDisconnect, |
| this)); |
| return RespondLater(); |
| } |
| |
| void AutotestPrivateBootstrapMachineLearningServiceFunction::ModelLoaded( |
| chromeos::machine_learning::mojom::LoadModelResult result) { |
| if (result == chromeos::machine_learning::mojom::LoadModelResult::OK) { |
| Respond(NoArguments()); |
| } else { |
| Respond(Error(base::StrCat( |
| {"Model load error ", (std::ostringstream() << result).str()}))); |
| } |
| } |
| |
| void AutotestPrivateBootstrapMachineLearningServiceFunction:: |
| OnMojoDisconnect() { |
| Respond(Error("ML Service connection error")); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateSetAssistantEnabled |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateSetAssistantEnabledFunction:: |
| AutotestPrivateSetAssistantEnabledFunction() { |
| // |AddObserver| will immediately trigger |OnAssistantStatusChanged|. |
| ash::AssistantState::Get()->AddObserver(this); |
| } |
| |
| AutotestPrivateSetAssistantEnabledFunction:: |
| ~AutotestPrivateSetAssistantEnabledFunction() { |
| ash::AssistantState::Get()->RemoveObserver(this); |
| } |
| |
| ExtensionFunction::ResponseAction |
| AutotestPrivateSetAssistantEnabledFunction::Run() { |
| DVLOG(1) << "AutotestPrivateSetAssistantEnabledFunction"; |
| |
| std::unique_ptr<api::autotest_private::SetAssistantEnabled::Params> params( |
| api::autotest_private::SetAssistantEnabled::Params::Create(*args_)); |
| EXTENSION_FUNCTION_VALIDATE(params); |
| |
| Profile* profile = Profile::FromBrowserContext(browser_context()); |
| const std::string& err_msg = |
| SetWhitelistedPref(profile, chromeos::assistant::prefs::kAssistantEnabled, |
| base::Value(params->enabled)); |
| if (!err_msg.empty()) |
| return RespondNow(Error(err_msg)); |
| |
| // Any state that's not |NOT_READY| would be considered a ready state. |
| const bool not_ready = (ash::AssistantState::Get()->assistant_status() == |
| chromeos::assistant::AssistantStatus::NOT_READY); |
| const bool success = (params->enabled != not_ready); |
| if (success) |
| return RespondNow(NoArguments()); |
| |
| // Assistant service has not responded yet, set up a delayed timer to wait for |
| // it and holder a reference to |this|. Also make sure we stop and respond |
| // when timeout. |
| enabled_ = params->enabled; |
| timeout_timer_.Start( |
| FROM_HERE, base::TimeDelta::FromMilliseconds(params->timeout_ms), |
| base::BindOnce(&AutotestPrivateSetAssistantEnabledFunction::Timeout, |
| this)); |
| return RespondLater(); |
| } |
| |
| void AutotestPrivateSetAssistantEnabledFunction::OnAssistantStatusChanged( |
| chromeos::assistant::AssistantStatus status) { |
| // Must check if the Optional contains value first to avoid possible |
| // segmentation fault caused by Respond() below being called before |
| // RespondLater() in Run(). This will happen due to AddObserver() call |
| // in the constructor will trigger this function immediately. |
| if (!enabled_.has_value()) |
| return; |
| |
| const bool not_ready = |
| (status == chromeos::assistant::AssistantStatus::NOT_READY); |
| const bool success = (enabled_.value() != not_ready); |
| if (!success) |
| return; |
| |
| Respond(NoArguments()); |
| enabled_.reset(); |
| timeout_timer_.AbandonAndStop(); |
| } |
| |
| void AutotestPrivateSetAssistantEnabledFunction::Timeout() { |
| DCHECK(!did_respond()); |
| Respond(Error("Assistant service timed out")); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateEnableAssistantAndWaitForReadyFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateEnableAssistantAndWaitForReadyFunction:: |
| AutotestPrivateEnableAssistantAndWaitForReadyFunction() = default; |
| |
| AutotestPrivateEnableAssistantAndWaitForReadyFunction:: |
| ~AutotestPrivateEnableAssistantAndWaitForReadyFunction() { |
| ash::AssistantState::Get()->RemoveObserver(this); |
| } |
| |
| ExtensionFunction::ResponseAction |
| AutotestPrivateEnableAssistantAndWaitForReadyFunction::Run() { |
| DVLOG(1) << "AutotestPrivateEnableAssistantAndWaitForReadyFunction"; |
| |
| Profile* profile = Profile::FromBrowserContext(browser_context()); |
| const std::string& err_msg = |
| SetWhitelistedPref(profile, chromeos::assistant::prefs::kAssistantEnabled, |
| base::Value(true)); |
| if (!err_msg.empty()) |
| return RespondNow(Error(err_msg)); |
| |
| // Asynchronously subscribe to status changes to avoid a possible segmentation |
| // fault caused by Respond() in the subscriber callback being called before |
| // RespondLater() below. |
| base::SequencedTaskRunnerHandle::Get()->PostTask( |
| FROM_HERE, |
| base::BindOnce(&AutotestPrivateEnableAssistantAndWaitForReadyFunction:: |
| SubscribeToStatusChanges, |
| this)); |
| |
| // Prevent |this| from being freed before we get a response from the |
| // Assistant. |
| self_ = this; |
| |
| return RespondLater(); |
| } |
| |
| void AutotestPrivateEnableAssistantAndWaitForReadyFunction:: |
| SubscribeToStatusChanges() { |
| // |AddObserver| will immediately trigger |OnAssistantStatusChanged|. |
| ash::AssistantState::Get()->AddObserver(this); |
| } |
| |
| void AutotestPrivateEnableAssistantAndWaitForReadyFunction:: |
| OnAssistantStatusChanged(chromeos::assistant::AssistantStatus status) { |
| if (status == chromeos::assistant::AssistantStatus::READY) { |
| Respond(NoArguments()); |
| self_.reset(); |
| } |
| } |
| |
| // AssistantInteractionHelper is a helper class used to interact with Assistant |
| // server and store interaction states for tests. It is shared by |
| // |AutotestPrivateSendAssistantTextQueryFunction| and |
| // |AutotestPrivateWaitForAssistantQueryStatusFunction|. |
| class AssistantInteractionHelper |
| : public chromeos::assistant::AssistantInteractionSubscriber { |
| public: |
| using OnInteractionFinishedCallback = |
| base::OnceCallback<void(const absl::optional<std::string>& error)>; |
| |
| AssistantInteractionHelper() |
| : query_status_(std::make_unique<base::DictionaryValue>()) {} |
| |
| ~AssistantInteractionHelper() override { |
| if (GetAssistant()) { |
| GetAssistant()->RemoveAssistantInteractionSubscriber(this); |
| } |
| } |
| |
| void Init(OnInteractionFinishedCallback on_interaction_finished_callback) { |
| // Subscribe to Assistant interaction events. |
| GetAssistant()->AddAssistantInteractionSubscriber(this); |
| |
| on_interaction_finished_callback_ = |
| std::move(on_interaction_finished_callback); |
| } |
| |
| void SendTextQuery(const std::string& query, bool allow_tts) { |
| // Start text interaction with Assistant server. |
| GetAssistant()->StartTextInteraction( |
| query, chromeos::assistant::AssistantQuerySource::kUnspecified, |
| allow_tts); |
| |
| query_status_->SetKey("queryText", base::Value(query)); |
| } |
| |
| std::unique_ptr<base::DictionaryValue> GetQueryStatus() { |
| return std::move(query_status_); |
| } |
| |
| chromeos::assistant::Assistant* GetAssistant() { |
| auto* assistant_service = chromeos::assistant::AssistantService::Get(); |
| return assistant_service ? assistant_service->GetAssistant() : nullptr; |
| } |
| |
| private: |
| // chromeos::assistant::AssistantInteractionSubscriber: |
| using AssistantSuggestion = chromeos::assistant::AssistantSuggestion; |
| using AssistantInteractionMetadata = |
| chromeos::assistant::AssistantInteractionMetadata; |
| using AssistantInteractionResolution = |
| chromeos::assistant::AssistantInteractionResolution; |
| |
| void OnInteractionStarted( |
| const AssistantInteractionMetadata& metadata) override { |
| const bool is_voice_interaction = |
| chromeos::assistant::AssistantInteractionType::kVoice == metadata.type; |
| query_status_->SetKey("isMicOpen", base::Value(is_voice_interaction)); |
| interaction_in_progress_ = true; |
| } |
| |
| void OnInteractionFinished( |
| AssistantInteractionResolution resolution) override { |
| interaction_in_progress_ = false; |
| |
| // Only invoke the callback when |result_| is not empty to avoid an early |
| // return before the entire session is completed. This happens when |
| // sending queries to modify device settings, e.g. "turn on bluetooth", |
| // which results in a round trip due to the need to fetch device state |
| // on the client and return that to the server as part of a follow-up |
| // interaction. |
| if (result_.DictEmpty()) |
| return; |
| |
| query_status_->SetKey("queryResponse", std::move(result_)); |
| |
| if (on_interaction_finished_callback_) { |
| if (resolution == AssistantInteractionResolution::kNormal) { |
| SendSuccessResponse(); |
| } else { |
| SendErrorResponse("Interaction closed with resolution " + |
| ResolutionToString(resolution)); |
| } |
| } |
| } |
| |
| void OnHtmlResponse(const std::string& response, |
| const std::string& fallback) override { |
| result_.SetKey("htmlResponse", base::Value(response)); |
| CheckResponseIsValid(__FUNCTION__); |
| } |
| |
| void OnTextResponse(const std::string& response) override { |
| result_.SetKey("text", base::Value(response)); |
| CheckResponseIsValid(__FUNCTION__); |
| } |
| |
| void OnOpenUrlResponse(const ::GURL& url, bool in_background) override { |
| result_.SetKey("openUrl", base::Value(url.possibly_invalid_spec())); |
| } |
| |
| void OnOpenAppResponse( |
| const chromeos::assistant::AndroidAppInfo& app_info) override { |
| result_.SetKey("openAppResponse", base::Value(app_info.package_name)); |
| CheckResponseIsValid(__FUNCTION__); |
| } |
| |
| void OnSpeechRecognitionFinalResult( |
| const std::string& final_result) override { |
| query_status_->SetKey("queryText", base::Value(final_result)); |
| } |
| |
| void CheckResponseIsValid(const std::string& function_name) { |
| if (!interaction_in_progress_) { |
| // We should only get a response while the interaction is open |
| // (started and not finished). |
| SendErrorResponse(function_name + |
| " was called after the interaction was closed"); |
| } |
| } |
| |
| void SendSuccessResponse() { |
| std::move(on_interaction_finished_callback_).Run(absl::nullopt); |
| } |
| |
| void SendErrorResponse(const std::string& error) { |
| std::move(on_interaction_finished_callback_).Run(error); |
| } |
| |
| std::unique_ptr<base::DictionaryValue> query_status_; |
| base::DictionaryValue result_; |
| bool interaction_in_progress_ = false; |
| |
| // Callback triggered when interaction finished with non-empty response. |
| OnInteractionFinishedCallback on_interaction_finished_callback_; |
| |
| DISALLOW_COPY_AND_ASSIGN(AssistantInteractionHelper); |
| }; |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateSendAssistantTextQueryFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateSendAssistantTextQueryFunction:: |
| AutotestPrivateSendAssistantTextQueryFunction() |
| : interaction_helper_(std::make_unique<AssistantInteractionHelper>()) {} |
| |
| AutotestPrivateSendAssistantTextQueryFunction:: |
| ~AutotestPrivateSendAssistantTextQueryFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| AutotestPrivateSendAssistantTextQueryFunction::Run() { |
| DVLOG(1) << "AutotestPrivateSendAssistantTextQueryFunction"; |
| |
| std::unique_ptr<api::autotest_private::SendAssistantTextQuery::Params> params( |
| api::autotest_private::SendAssistantTextQuery::Params::Create(*args_)); |
| EXTENSION_FUNCTION_VALIDATE(params); |
| |
| Profile* profile = Profile::FromBrowserContext(browser_context()); |
| chromeos::assistant::AssistantAllowedState allowed_state = |
| assistant::IsAssistantAllowedForProfile(profile); |
| if (allowed_state != chromeos::assistant::AssistantAllowedState::ALLOWED) { |
| return RespondNow(Error(base::StringPrintf( |
| "Assistant not allowed - state: %d", allowed_state))); |
| } |
| |
| interaction_helper_->Init( |
| base::BindOnce(&AutotestPrivateSendAssistantTextQueryFunction:: |
| OnInteractionFinishedCallback, |
| this)); |
| |
| // Start text interaction with Assistant server. |
| interaction_helper_->SendTextQuery(params->query, /*allow_tts=*/false); |
| |
| // Set up a delayed timer to wait for the query response and hold a reference |
| // to |this| to avoid being destructed. Also make sure we stop and respond |
| // when timeout. |
| timeout_timer_.Start( |
| FROM_HERE, base::TimeDelta::FromMilliseconds(params->timeout_ms), |
| base::BindOnce(&AutotestPrivateSendAssistantTextQueryFunction::Timeout, |
| this)); |
| |
| return RespondLater(); |
| } |
| |
| void AutotestPrivateSendAssistantTextQueryFunction:: |
| OnInteractionFinishedCallback(const absl::optional<std::string>& error) { |
| DCHECK(!did_respond()); |
| if (error) { |
| Respond(Error(error.value())); |
| } else { |
| Respond(OneArgument(base::Value::FromUniquePtrValue( |
| interaction_helper_->GetQueryStatus()))); |
| } |
| |
| // |timeout_timer_| need to be hold until |Respond(.)| is called to avoid |
| // |this| being destructed. |
| timeout_timer_.AbandonAndStop(); |
| } |
| |
| void AutotestPrivateSendAssistantTextQueryFunction::Timeout() { |
| DCHECK(!did_respond()); |
| Respond(Error("Assistant response timeout.")); |
| |
| // Reset to unsubscribe OnInteractionFinishedCallback(). |
| interaction_helper_.reset(); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateWaitForAssistantQueryStatusFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| AutotestPrivateWaitForAssistantQueryStatusFunction:: |
| AutotestPrivateWaitForAssistantQueryStatusFunction() |
| : interaction_helper_(std::make_unique<AssistantInteractionHelper>()) {} |
| |
| AutotestPrivateWaitForAssistantQueryStatusFunction:: |
| ~AutotestPrivateWaitForAssistantQueryStatusFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| AutotestPrivateWaitForAssistantQueryStatusFunction::Run() { |
| DVLOG(1) << "AutotestPrivateWaitForAssistantQueryStatusFunction"; |
| |
| std::unique_ptr<api::autotest_private::WaitForAssistantQueryStatus::Params> |
| params(api::autotest_private::WaitForAssistantQueryStatus::Params::Create( |
| *args_)); |
| EXTENSION_FUNCTION_VALIDATE(params); |
| |
| Profile* profile = Profile::FromBrowserContext(browser_context()); |
| chromeos::assistant::AssistantAllowedState allowed_state = |
| assistant::IsAssistantAllowedForProfile(profile); |
| if (allowed_state != chromeos::assistant::AssistantAllowedState::ALLOWED) { |
| return RespondNow(Error(base::StringPrintf( |
| "Assistant not allowed - state: %d", allowed_state))); |
| } |
| |
| interaction_helper_->Init( |
| base::BindOnce(&AutotestPrivateWaitForAssistantQueryStatusFunction:: |
| OnInteractionFinishedCallback, |
| this)); |
| |
| // Start waiting for the response before time out. |
| timeout_timer_.Start( |
| FROM_HERE, base::TimeDelta::FromSeconds(params->timeout_s), |
| base::BindOnce( |
| &AutotestPrivateWaitForAssistantQueryStatusFunction::Timeout, this)); |
| return RespondLater(); |
| } |
| |
| void AutotestPrivateWaitForAssistantQueryStatusFunction:: |
| OnInteractionFinishedCallback(const absl::optional<std::string>& error) { |
| DCHECK(!did_respond()); |
| if (error) { |
| Respond(Error(error.value())); |
| } else { |
| Respond(OneArgument(base::Value::FromUniquePtrValue( |
| interaction_helper_->GetQueryStatus()))); |
| } |
| |
| // |timeout_timer_| need to be hold until |Respond(.)| is called to avoid |
| // |this| being destructed. |
| timeout_timer_.AbandonAndStop(); |
| } |
| |
| void AutotestPrivateWaitForAssistantQueryStatusFunction::Timeout() { |
| DCHECK(!did_respond()); |
| Respond(Error("No query response received before time out.")); |
| |
| // Reset to unsubscribe OnInteractionFinishedCallback(). |
| interaction_helper_.reset(); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateIsArcPackageListInitialRefreshedFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateIsArcPackageListInitialRefreshedFunction:: |
| AutotestPrivateIsArcPackageListInitialRefreshedFunction() = default; |
| |
| AutotestPrivateIsArcPackageListInitialRefreshedFunction:: |
| ~AutotestPrivateIsArcPackageListInitialRefreshedFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| AutotestPrivateIsArcPackageListInitialRefreshedFunction::Run() { |
| DVLOG(1) << "AutotestPrivateIsArcPackageListInitialRefreshedFunction"; |
| |
| ArcAppListPrefs* const prefs = |
| ArcAppListPrefs::Get(Profile::FromBrowserContext(browser_context())); |
| |
| return RespondNow( |
| OneArgument(base::Value(prefs->package_list_initial_refreshed()))); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateSetWhitelistedPrefFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateSetWhitelistedPrefFunction:: |
| ~AutotestPrivateSetWhitelistedPrefFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| AutotestPrivateSetWhitelistedPrefFunction::Run() { |
| DVLOG(1) << "AutotestPrivateSetWhitelistedPrefFunction"; |
| |
| std::unique_ptr<api::autotest_private::SetWhitelistedPref::Params> params( |
| api::autotest_private::SetWhitelistedPref::Params::Create(*args_)); |
| EXTENSION_FUNCTION_VALIDATE(params); |
| |
| const std::string& pref_name = params->pref_name; |
| const base::Value& value = *(params->value); |
| |
| Profile* profile = Profile::FromBrowserContext(browser_context()); |
| const std::string& err_msg = SetWhitelistedPref(profile, pref_name, value); |
| |
| if (!err_msg.empty()) |
| return RespondNow(Error(err_msg)); |
| |
| return RespondNow(NoArguments()); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateSetCrostiniAppScaledFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateSetCrostiniAppScaledFunction:: |
| ~AutotestPrivateSetCrostiniAppScaledFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| AutotestPrivateSetCrostiniAppScaledFunction::Run() { |
| std::unique_ptr<api::autotest_private::SetCrostiniAppScaled::Params> params( |
| api::autotest_private::SetCrostiniAppScaled::Params::Create(*args_)); |
| EXTENSION_FUNCTION_VALIDATE(params); |
| DVLOG(1) << "AutotestPrivateSetCrostiniAppScaledFunction " << params->app_id |
| << " " << params->scaled; |
| |
| ChromeShelfController* const controller = ChromeShelfController::instance(); |
| if (!controller) |
| return RespondNow(Error("Controller not available")); |
| |
| auto* registry_service = |
| guest_os::GuestOsRegistryServiceFactory::GetForProfile( |
| controller->profile()); |
| if (!registry_service) |
| return RespondNow(Error("Crostini registry not available")); |
| |
| registry_service->SetAppScaled(params->app_id, params->scaled); |
| return RespondNow(NoArguments()); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateGetPrimaryDisplayScaleFactorFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateGetPrimaryDisplayScaleFactorFunction:: |
| ~AutotestPrivateGetPrimaryDisplayScaleFactorFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| AutotestPrivateGetPrimaryDisplayScaleFactorFunction::Run() { |
| DVLOG(1) << "AutotestPrivateGetPrimaryDisplayScaleFactorFunction"; |
| |
| display::Display primary_display = |
| display::Screen::GetScreen()->GetPrimaryDisplay(); |
| float scale_factor = primary_display.device_scale_factor(); |
| return RespondNow(OneArgument(base::Value(scale_factor))); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateIsTabletModeEnabledFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateIsTabletModeEnabledFunction:: |
| ~AutotestPrivateIsTabletModeEnabledFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| AutotestPrivateIsTabletModeEnabledFunction::Run() { |
| DVLOG(1) << "AutotestPrivateIsTabletModeEnabledFunction"; |
| |
| return RespondNow( |
| OneArgument(base::Value(ash::TabletMode::Get()->InTabletMode()))); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateSetTabletModeEnabledFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateSetTabletModeEnabledFunction:: |
| ~AutotestPrivateSetTabletModeEnabledFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| AutotestPrivateSetTabletModeEnabledFunction::Run() { |
| DVLOG(1) << "AutotestPrivateSetTabletModeEnabledFunction"; |
| |
| std::unique_ptr<api::autotest_private::SetTabletModeEnabled::Params> params( |
| api::autotest_private::SetTabletModeEnabled::Params::Create(*args_)); |
| EXTENSION_FUNCTION_VALIDATE(params); |
| auto* tablet_mode = ash::TabletMode::Get(); |
| if (tablet_mode->InTabletMode() == params->enabled) { |
| return RespondNow( |
| OneArgument(base::Value(ash::TabletMode::Get()->InTabletMode()))); |
| } |
| |
| ash::TabletMode::Waiter waiter(params->enabled); |
| if (!tablet_mode->ForceUiTabletModeState(params->enabled)) |
| return RespondNow(Error("failed to switch the tablet mode state")); |
| waiter.Wait(); |
| return RespondNow( |
| OneArgument(base::Value(ash::TabletMode::Get()->InTabletMode()))); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateGetAllInstalledAppsFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| AutotestPrivateGetAllInstalledAppsFunction:: |
| AutotestPrivateGetAllInstalledAppsFunction() = default; |
| |
| AutotestPrivateGetAllInstalledAppsFunction:: |
| ~AutotestPrivateGetAllInstalledAppsFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| AutotestPrivateGetAllInstalledAppsFunction::Run() { |
| DVLOG(1) << "AutotestPrivateGetAllInstalledAppsFunction"; |
| |
| Profile* const profile = Profile::FromBrowserContext(browser_context()); |
| apps::AppServiceProxyChromeOs* proxy = |
| apps::AppServiceProxyFactory::GetForProfile(profile); |
| |
| std::vector<api::autotest_private::App> installed_apps; |
| proxy->AppRegistryCache().ForEachApp([&installed_apps]( |
| const apps::AppUpdate& update) { |
| api::autotest_private::App app; |
| app.app_id = update.AppId(); |
| app.name = update.Name(); |
| app.short_name = update.ShortName(); |
| app.publisher_id = update.PublisherId(); |
| app.additional_search_terms = update.AdditionalSearchTerms(); |
| app.type = GetAppType(update.AppType()); |
| app.install_source = GetAppInstallSource(update.InstallSource()); |
| app.readiness = GetAppReadiness(update.Readiness()); |
| app.show_in_launcher = ConvertMojomOptionalBool(update.ShowInLauncher()); |
| app.show_in_search = ConvertMojomOptionalBool(update.ShowInSearch()); |
| installed_apps.emplace_back(std::move(app)); |
| }); |
| |
| return RespondNow( |
| ArgumentList(api::autotest_private::GetAllInstalledApps::Results::Create( |
| installed_apps))); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateGetShelfItemsFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| AutotestPrivateGetShelfItemsFunction::AutotestPrivateGetShelfItemsFunction() = |
| default; |
| |
| AutotestPrivateGetShelfItemsFunction::~AutotestPrivateGetShelfItemsFunction() = |
| default; |
| |
| ExtensionFunction::ResponseAction AutotestPrivateGetShelfItemsFunction::Run() { |
| DVLOG(1) << "AutotestPrivateGetShelfItemsFunction"; |
| |
| ChromeShelfController* const controller = ChromeShelfController::instance(); |
| if (!controller) |
| return RespondNow(Error("Controller not available")); |
| |
| std::vector<api::autotest_private::ShelfItem> result_items; |
| for (const auto& item : controller->shelf_model()->items()) { |
| api::autotest_private::ShelfItem result_item; |
| result_item.app_id = item.id.app_id; |
| result_item.launch_id = item.id.launch_id; |
| result_item.title = base::UTF16ToUTF8(item.title); |
| result_item.type = GetShelfItemType(item.type); |
| result_item.status = GetShelfItemStatus(item.status); |
| result_item.shows_tooltip = item.shows_tooltip; |
| result_item.pinned_by_policy = item.pinned_by_policy; |
| result_item.has_notification = item.has_notification; |
| result_items.emplace_back(std::move(result_item)); |
| } |
| |
| return RespondNow(ArgumentList( |
| api::autotest_private::GetShelfItems::Results::Create(result_items))); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateGetShelfAutoHideBehaviorFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateGetShelfAutoHideBehaviorFunction:: |
| AutotestPrivateGetShelfAutoHideBehaviorFunction() = default; |
| |
| AutotestPrivateGetShelfAutoHideBehaviorFunction:: |
| ~AutotestPrivateGetShelfAutoHideBehaviorFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| AutotestPrivateGetShelfAutoHideBehaviorFunction::Run() { |
| DVLOG(1) << "AutotestPrivateGetShelfAutoHideBehaviorFunction"; |
| |
| std::unique_ptr<api::autotest_private::GetShelfAutoHideBehavior::Params> |
| params(api::autotest_private::GetShelfAutoHideBehavior::Params::Create( |
| *args_)); |
| EXTENSION_FUNCTION_VALIDATE(params); |
| |
| int64_t display_id; |
| if (!base::StringToInt64(params->display_id, &display_id)) { |
| return RespondNow(Error(base::StrCat( |
| {"Invalid display_id; expected string with numbers only, got ", |
| params->display_id}))); |
| } |
| |
| Profile* const profile = Profile::FromBrowserContext(browser_context()); |
| ash::ShelfAutoHideBehavior behavior = |
| ash::GetShelfAutoHideBehaviorPref(profile->GetPrefs(), display_id); |
| std::string str_behavior; |
| switch (behavior) { |
| case ash::ShelfAutoHideBehavior::kAlways: |
| str_behavior = "always"; |
| break; |
| case ash::ShelfAutoHideBehavior::kNever: |
| str_behavior = "never"; |
| break; |
| case ash::ShelfAutoHideBehavior::kAlwaysHidden: |
| // SHELF_AUTO_HIDE_ALWAYS_HIDDEN not supported by shelf_prefs.cc |
| return RespondNow(Error("SHELF_AUTO_HIDE_ALWAYS_HIDDEN not supported")); |
| } |
| return RespondNow(OneArgument(base::Value(std::move(str_behavior)))); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateSetShelfAutoHideBehaviorFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateSetShelfAutoHideBehaviorFunction:: |
| AutotestPrivateSetShelfAutoHideBehaviorFunction() = default; |
| |
| AutotestPrivateSetShelfAutoHideBehaviorFunction:: |
| ~AutotestPrivateSetShelfAutoHideBehaviorFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| AutotestPrivateSetShelfAutoHideBehaviorFunction::Run() { |
| DVLOG(1) << "AutotestPrivateSetShelfAutoHideBehaviorFunction"; |
| |
| std::unique_ptr<api::autotest_private::SetShelfAutoHideBehavior::Params> |
| params(api::autotest_private::SetShelfAutoHideBehavior::Params::Create( |
| *args_)); |
| EXTENSION_FUNCTION_VALIDATE(params); |
| |
| ash::ShelfAutoHideBehavior behavior; |
| if (params->behavior == "always") { |
| behavior = ash::ShelfAutoHideBehavior::kAlways; |
| } else if (params->behavior == "never") { |
| behavior = ash::ShelfAutoHideBehavior::kNever; |
| } else { |
| return RespondNow(Error( |
| base::StrCat({"Invalid behavior; expected 'always', 'never', got ", |
| params->behavior}))); |
| } |
| int64_t display_id; |
| if (!base::StringToInt64(params->display_id, &display_id)) { |
| return RespondNow(Error(base::StrCat( |
| {"Invalid display_id; expected string with numbers only, got ", |
| params->display_id}))); |
| } |
| |
| Profile* const profile = Profile::FromBrowserContext(browser_context()); |
| ash::SetShelfAutoHideBehaviorPref(profile->GetPrefs(), display_id, behavior); |
| return RespondNow(NoArguments()); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateGetShelfAlignmentFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateGetShelfAlignmentFunction:: |
| AutotestPrivateGetShelfAlignmentFunction() = default; |
| |
| AutotestPrivateGetShelfAlignmentFunction:: |
| ~AutotestPrivateGetShelfAlignmentFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| AutotestPrivateGetShelfAlignmentFunction::Run() { |
| DVLOG(1) << "AutotestPrivateGetShelfAlignmentFunction"; |
| |
| std::unique_ptr<api::autotest_private::GetShelfAlignment::Params> params( |
| api::autotest_private::GetShelfAlignment::Params::Create(*args_)); |
| EXTENSION_FUNCTION_VALIDATE(params); |
| |
| int64_t display_id; |
| if (!base::StringToInt64(params->display_id, &display_id)) { |
| return RespondNow(Error(base::StrCat( |
| {"Invalid display_id; expected string with numbers only, got ", |
| params->display_id}))); |
| } |
| |
| Profile* const profile = Profile::FromBrowserContext(browser_context()); |
| ash::ShelfAlignment alignment = |
| ash::GetShelfAlignmentPref(profile->GetPrefs(), display_id); |
| api::autotest_private::ShelfAlignmentType alignment_type; |
| switch (alignment) { |
| case ash::ShelfAlignment::kBottom: |
| alignment_type = api::autotest_private::ShelfAlignmentType:: |
| SHELF_ALIGNMENT_TYPE_BOTTOM; |
| break; |
| case ash::ShelfAlignment::kLeft: |
| alignment_type = |
| api::autotest_private::ShelfAlignmentType::SHELF_ALIGNMENT_TYPE_LEFT; |
| break; |
| case ash::ShelfAlignment::kRight: |
| alignment_type = |
| api::autotest_private::ShelfAlignmentType::SHELF_ALIGNMENT_TYPE_RIGHT; |
| break; |
| case ash::ShelfAlignment::kBottomLocked: |
| // ShelfAlignment::kBottomLocked not supported by |
| // shelf_prefs.cc |
| return RespondNow(Error("ShelfAlignment::kBottomLocked not supported")); |
| } |
| return RespondNow(OneArgument( |
| base::Value(api::autotest_private::ToString(alignment_type)))); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateSetShelfAlignmentFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateSetShelfAlignmentFunction:: |
| AutotestPrivateSetShelfAlignmentFunction() = default; |
| |
| AutotestPrivateSetShelfAlignmentFunction:: |
| ~AutotestPrivateSetShelfAlignmentFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| AutotestPrivateSetShelfAlignmentFunction::Run() { |
| DVLOG(1) << "AutotestPrivateSetShelfAlignmentFunction"; |
| |
| std::unique_ptr<api::autotest_private::SetShelfAlignment::Params> params( |
| api::autotest_private::SetShelfAlignment::Params::Create(*args_)); |
| EXTENSION_FUNCTION_VALIDATE(params); |
| |
| ash::ShelfAlignment alignment; |
| switch (params->alignment) { |
| case api::autotest_private::ShelfAlignmentType::SHELF_ALIGNMENT_TYPE_BOTTOM: |
| alignment = ash::ShelfAlignment::kBottom; |
| break; |
| case api::autotest_private::ShelfAlignmentType::SHELF_ALIGNMENT_TYPE_LEFT: |
| alignment = ash::ShelfAlignment::kLeft; |
| break; |
| case api::autotest_private::ShelfAlignmentType::SHELF_ALIGNMENT_TYPE_RIGHT: |
| alignment = ash::ShelfAlignment::kRight; |
| break; |
| case api::autotest_private::ShelfAlignmentType::SHELF_ALIGNMENT_TYPE_NONE: |
| return RespondNow( |
| Error("Invalid None alignment; expected 'Bottom', 'Left', or " |
| "'Right'")); |
| } |
| int64_t display_id; |
| if (!base::StringToInt64(params->display_id, &display_id)) { |
| return RespondNow(Error(base::StrCat( |
| {"Invalid display_id; expected string with numbers only, got ", |
| params->display_id}))); |
| } |
| |
| Profile* const profile = Profile::FromBrowserContext(browser_context()); |
| ash::SetShelfAlignmentPref(profile->GetPrefs(), display_id, alignment); |
| return RespondNow(NoArguments()); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateWaitForOverviewStateFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateWaitForOverviewStateFunction:: |
| AutotestPrivateWaitForOverviewStateFunction() = default; |
| AutotestPrivateWaitForOverviewStateFunction:: |
| ~AutotestPrivateWaitForOverviewStateFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| AutotestPrivateWaitForOverviewStateFunction::Run() { |
| std::unique_ptr<api::autotest_private::WaitForOverviewState::Params> params( |
| api::autotest_private::WaitForOverviewState::Params::Create(*args_)); |
| EXTENSION_FUNCTION_VALIDATE(params); |
| const ash::OverviewAnimationState overview_state = |
| ToOverviewAnimationState(params->overview_state); |
| ash::OverviewTestApi().WaitForOverviewState( |
| overview_state, |
| base::BindOnce(&AutotestPrivateWaitForOverviewStateFunction::Done, this)); |
| return did_respond() ? AlreadyResponded() : RespondLater(); |
| } |
| |
| void AutotestPrivateWaitForOverviewStateFunction::Done(bool success) { |
| if (!success) { |
| Respond(Error("Overview animation was canceled.")); |
| return; |
| } |
| Respond(NoArguments()); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateSetOverviewModeStateFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateSetOverviewModeStateFunction:: |
| AutotestPrivateSetOverviewModeStateFunction() = default; |
| |
| AutotestPrivateSetOverviewModeStateFunction:: |
| ~AutotestPrivateSetOverviewModeStateFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| AutotestPrivateSetOverviewModeStateFunction::Run() { |
| std::unique_ptr<api::autotest_private::SetOverviewModeState::Params> params( |
| api::autotest_private::SetOverviewModeState::Params::Create(*args_)); |
| EXTENSION_FUNCTION_VALIDATE(params); |
| |
| ash::OverviewTestApi().SetOverviewMode( |
| params->start, |
| base::BindOnce( |
| &AutotestPrivateSetOverviewModeStateFunction::OnOverviewModeChanged, |
| this, params->start)); |
| return did_respond() ? AlreadyResponded() : RespondLater(); |
| } |
| |
| void AutotestPrivateSetOverviewModeStateFunction::OnOverviewModeChanged( |
| bool for_start, |
| bool finished) { |
| auto arg = OneArgument(base::Value(finished)); |
| // On starting the overview animation, it needs to wait for 1 extra second |
| // to trigger the occlusion tracker. |
| if (for_start) { |
| base::SequencedTaskRunnerHandle::Get()->PostDelayedTask( |
| FROM_HERE, |
| base::BindOnce(&AutotestPrivateSetOverviewModeStateFunction::Respond, |
| this, std::move(arg)), |
| base::TimeDelta::FromSeconds(1)); |
| } else { |
| Respond(std::move(arg)); |
| } |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateShowVirtualKeyboardIfEnabledFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateShowVirtualKeyboardIfEnabledFunction:: |
| AutotestPrivateShowVirtualKeyboardIfEnabledFunction() = default; |
| AutotestPrivateShowVirtualKeyboardIfEnabledFunction:: |
| ~AutotestPrivateShowVirtualKeyboardIfEnabledFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| AutotestPrivateShowVirtualKeyboardIfEnabledFunction::Run() { |
| if (!ui::IMEBridge::Get() || |
| !ui::IMEBridge::Get()->GetInputContextHandler() || |
| !ui::IMEBridge::Get()->GetInputContextHandler()->GetInputMethod()) { |
| return RespondNow(NoArguments()); |
| } |
| |
| ui::IMEBridge::Get() |
| ->GetInputContextHandler() |
| ->GetInputMethod() |
| ->ShowVirtualKeyboardIfEnabled(); |
| return RespondNow(NoArguments()); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateArcAppTracingStartFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateArcAppTracingStartFunction:: |
| AutotestPrivateArcAppTracingStartFunction() = default; |
| AutotestPrivateArcAppTracingStartFunction:: |
| ~AutotestPrivateArcAppTracingStartFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| AutotestPrivateArcAppTracingStartFunction::Run() { |
| DVLOG(1) << "AutotestPrivateArcAppTracingStartFunction"; |
| |
| arc::ArcAppPerformanceTracing* const tracing = |
| arc::ArcAppPerformanceTracing::GetForBrowserContext(browser_context()); |
| if (!tracing) |
| return RespondNow(Error("No ARC performance tracing is available.")); |
| |
| if (!tracing->StartCustomTracing()) |
| return RespondNow(Error("Failed to start custom tracing.")); |
| |
| return RespondNow(NoArguments()); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateArcAppTracingStopAndAnalyzeFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateArcAppTracingStopAndAnalyzeFunction:: |
| AutotestPrivateArcAppTracingStopAndAnalyzeFunction() = default; |
| AutotestPrivateArcAppTracingStopAndAnalyzeFunction:: |
| ~AutotestPrivateArcAppTracingStopAndAnalyzeFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| AutotestPrivateArcAppTracingStopAndAnalyzeFunction::Run() { |
| DVLOG(1) << "AutotestPrivateArcAppTracingStopAndAnalyzeFunction"; |
| |
| arc::ArcAppPerformanceTracing* const tracing = |
| arc::ArcAppPerformanceTracing::GetForBrowserContext(browser_context()); |
| if (!tracing) |
| return RespondNow(Error("No ARC performance tracing is available.")); |
| |
| tracing->StopCustomTracing(base::BindOnce( |
| &AutotestPrivateArcAppTracingStopAndAnalyzeFunction::OnTracingResult, |
| this)); |
| return did_respond() ? AlreadyResponded() : RespondLater(); |
| } |
| |
| void AutotestPrivateArcAppTracingStopAndAnalyzeFunction::OnTracingResult( |
| bool success, |
| double fps, |
| double commit_deviation, |
| double render_quality) { |
| auto result = std::make_unique<base::Value>(base::Value::Type::DICTIONARY); |
| result->SetBoolKey("success", success); |
| result->SetDoubleKey("fps", fps); |
| result->SetDoubleKey("commitDeviation", commit_deviation); |
| result->SetDoubleKey("renderQuality", render_quality); |
| Respond(OneArgument(base::Value::FromUniquePtrValue(std::move(result)))); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateSetArcAppWindowFocusFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateSetArcAppWindowFocusFunction:: |
| AutotestPrivateSetArcAppWindowFocusFunction() = default; |
| AutotestPrivateSetArcAppWindowFocusFunction:: |
| ~AutotestPrivateSetArcAppWindowFocusFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| AutotestPrivateSetArcAppWindowFocusFunction::Run() { |
| std::unique_ptr<api::autotest_private::SetArcAppWindowFocus::Params> params( |
| api::autotest_private::SetArcAppWindowFocus::Params::Create(*args_)); |
| EXTENSION_FUNCTION_VALIDATE(params); |
| DVLOG(1) << "AutotestPrivateSetArcAppWindowFocusFunction " |
| << params->package_name; |
| aura::Window* arc_window = GetArcAppWindow(params->package_name); |
| if (!arc_window) { |
| return RespondNow(Error(base::StrCat( |
| {"No ARC app window was found for ", params->package_name}))); |
| } |
| if (!arc_window->CanFocus()) { |
| return RespondNow(Error(base::StrCat( |
| {"ARC app window can't focus for ", params->package_name}))); |
| } |
| // No matter whether it is focused already, set it focused. |
| arc_window->Focus(); |
| if (!arc_window->HasFocus()) { |
| return RespondNow(Error(base::StrCat( |
| {"Failed to set focus for ARC App window ", params->package_name}))); |
| } |
| return RespondNow(NoArguments()); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateSwapWindowsInSplitViewFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateSwapWindowsInSplitViewFunction:: |
| AutotestPrivateSwapWindowsInSplitViewFunction() = default; |
| AutotestPrivateSwapWindowsInSplitViewFunction:: |
| ~AutotestPrivateSwapWindowsInSplitViewFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| AutotestPrivateSwapWindowsInSplitViewFunction::Run() { |
| ash::SplitViewTestApi().SwapWindows(); |
| return RespondNow(NoArguments()); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateWaitForDisplayRotationFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateWaitForDisplayRotationFunction:: |
| AutotestPrivateWaitForDisplayRotationFunction() = default; |
| AutotestPrivateWaitForDisplayRotationFunction:: |
| ~AutotestPrivateWaitForDisplayRotationFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| AutotestPrivateWaitForDisplayRotationFunction::Run() { |
| DVLOG(1) << "AutotestPrivateWaitForDisplayRotationFunction"; |
| |
| std::unique_ptr<api::autotest_private::WaitForDisplayRotation::Params> params( |
| api::autotest_private::WaitForDisplayRotation::Params::Create(*args_)); |
| EXTENSION_FUNCTION_VALIDATE(params); |
| if (!base::StringToInt64(params->display_id, &display_id_)) { |
| return RespondNow(Error(base::StrCat( |
| {"Invalid display_id; expected string with numbers only, got ", |
| params->display_id}))); |
| } |
| |
| if (params->rotation == |
| api::autotest_private::RotationType::ROTATION_TYPE_ROTATEANY) { |
| display::Display display; |
| if (!display::Screen::GetScreen()->GetDisplayWithDisplayId(display_id_, |
| &display)) { |
| return RespondNow(Error(base::StrCat( |
| {"Display is not found for display_id ", params->display_id}))); |
| } |
| DCHECK(display.is_valid()); |
| if (!display.IsInternal()) { |
| return RespondNow( |
| Error("RotateAny is valid only for the internal display")); |
| } |
| auto* screen_orientation_controller = |
| ash::Shell::Get()->screen_orientation_controller(); |
| if (screen_orientation_controller->user_rotation_locked()) { |
| self_ = this; |
| screen_orientation_controller->AddObserver(this); |
| return RespondLater(); |
| } |
| target_rotation_.reset(); |
| } else { |
| target_rotation_ = ToRotation(params->rotation); |
| } |
| |
| auto result = CheckScreenRotationAnimation(); |
| if (result) |
| return RespondNow(std::move(result)); |
| return RespondLater(); |
| } |
| |
| void AutotestPrivateWaitForDisplayRotationFunction:: |
| OnScreenCopiedBeforeRotation() {} |
| |
| void AutotestPrivateWaitForDisplayRotationFunction:: |
| OnScreenRotationAnimationFinished(ash::ScreenRotationAnimator* animator, |
| bool canceled) { |
| animator->RemoveObserver(this); |
| |
| display::Display display; |
| display::Screen::GetScreen()->GetDisplayWithDisplayId(display_id_, &display); |
| Respond(OneArgument(base::Value(display.is_valid() && |
| (!target_rotation_.has_value() || |
| display.rotation() == *target_rotation_)))); |
| self_.reset(); |
| } |
| |
| void AutotestPrivateWaitForDisplayRotationFunction:: |
| OnUserRotationLockChanged() { |
| auto* screen_orientation_controller = |
| ash::Shell::Get()->screen_orientation_controller(); |
| if (screen_orientation_controller->user_rotation_locked()) |
| return; |
| screen_orientation_controller->RemoveObserver(this); |
| self_.reset(); |
| target_rotation_.reset(); |
| auto result = CheckScreenRotationAnimation(); |
| // Wait for the rotation if unlocking causes rotation. |
| if (result) |
| Respond(std::move(result)); |
| } |
| |
| ExtensionFunction::ResponseValue |
| AutotestPrivateWaitForDisplayRotationFunction::CheckScreenRotationAnimation() { |
| auto* root_window = ash::Shell::GetRootWindowForDisplayId(display_id_); |
| if (!root_window) { |
| return Error(base::StringPrintf( |
| "Invalid display_id; no root window found for the display id %" PRId64, |
| display_id_)); |
| } |
| auto* animator = ash::ScreenRotationAnimator::GetForRootWindow(root_window); |
| if (!animator->IsRotating()) { |
| display::Display display; |
| display::Screen::GetScreen()->GetDisplayWithDisplayId(display_id_, |
| &display); |
| // This should never fail. |
| DCHECK(display.is_valid()); |
| return OneArgument(base::Value(!target_rotation_.has_value() || |
| display.rotation() == *target_rotation_)); |
| } |
| self_ = this; |
| |
| animator->AddObserver(this); |
| return nullptr; |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateGetAppWindowListFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateGetAppWindowListFunction:: |
| AutotestPrivateGetAppWindowListFunction() = default; |
| AutotestPrivateGetAppWindowListFunction:: |
| ~AutotestPrivateGetAppWindowListFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| AutotestPrivateGetAppWindowListFunction::Run() { |
| // Use negative number to avoid potential collision with normal use if any. |
| static int id_count = -10000; |
| |
| absl::optional<ash::OverviewInfo> overview_info = |
| ash::OverviewTestApi().GetOverviewInfo(); |
| |
| auto window_list = ash::GetAppWindowList(); |
| std::vector<api::autotest_private::AppWindowInfo> result_list; |
| |
| for (auto* window : window_list) { |
| if (window->GetId() == aura::Window::kInitialId) |
| window->SetId(id_count--); |
| api::autotest_private::AppWindowInfo window_info; |
| window_info.id = window->GetId(); |
| window_info.name = window->GetName(); |
| window_info.window_type = GetAppWindowType( |
| static_cast<ash::AppType>(window->GetProperty(aura::client::kAppType))); |
| window_info.state_type = |
| ToWindowStateType(window->GetProperty(chromeos::kWindowStateTypeKey)); |
| window_info.bounds_in_root = |
| ToBoundsDictionary(window->GetBoundsInRootWindow()); |
| window_info.target_bounds = ToBoundsDictionary(window->GetTargetBounds()); |
| window_info.display_id = base::NumberToString( |
| display::Screen::GetScreen()->GetDisplayNearestWindow(window).id()); |
| window_info.title = base::UTF16ToUTF8(window->GetTitle()); |
| window_info.is_animating = window->layer()->GetAnimator()->is_animating(); |
| window_info.is_visible = window->IsVisible(); |
| window_info.target_visibility = window->TargetVisibility(); |
| window_info.can_focus = window->CanFocus(); |
| window_info.has_focus = window->HasFocus(); |
| window_info.on_active_desk = |
| ash::DesksHelper::Get()->BelongsToActiveDesk(window); |
| window_info.is_active = wm::IsActiveWindow(window); |
| window_info.has_capture = window->HasCapture(); |
| window_info.can_resize = |
| (window->GetProperty(aura::client::kResizeBehaviorKey) & |
| aura::client::kResizeBehaviorCanResize) != 0; |
| |
| if (window->GetProperty(aura::client::kAppType) == |
| static_cast<int>(ash::AppType::ARC_APP)) { |
| std::string* package_name = window->GetProperty(ash::kArcPackageNameKey); |
| if (package_name) { |
| window_info.arc_package_name = |
| std::make_unique<std::string>(*package_name); |
| } else { |
| LOG(ERROR) << "The package name for window " << window->GetTitle() |
| << " (ID: " << window->GetId() |
| << ") isn't available even though it is an ARC window."; |
| } |
| |
| std::string* app_id = window->GetProperty(full_restore::kAppIdKey); |
| if (app_id) { |
| window_info.full_restore_window_app_id = |
| std::make_unique<std::string>(*app_id); |
| } |
| } |
| |
| // Frame information |
| auto* immersive_controller = chromeos::ImmersiveFullscreenController::Get( |
| views::Widget::GetWidgetForNativeWindow(window)); |
| if (immersive_controller) { |
| // The widget that hosts the immersive frame can be different from the |
| // application's widget itself. Use the widget from the immersive |
| // controller to obtain the FrameHeader. |
| auto* widget = immersive_controller->widget(); |
| if (immersive_controller->IsEnabled()) { |
| window_info.frame_mode = |
| api::autotest_private::FrameMode::FRAME_MODE_IMMERSIVE; |
| window_info.is_frame_visible = immersive_controller->IsRevealed(); |
| } else { |
| window_info.frame_mode = |
| api::autotest_private::FrameMode::FRAME_MODE_NORMAL; |
| window_info.is_frame_visible = IsFrameVisible(widget); |
| } |
| auto* frame_header = chromeos::FrameHeader::Get(widget); |
| window_info.caption_height = frame_header->GetHeaderHeight(); |
| |
| const chromeos::CaptionButtonModel* button_model = |
| frame_header->GetCaptionButtonModel(); |
| int caption_button_enabled_status = 0; |
| int caption_button_visible_status = 0; |
| |
| constexpr views::CaptionButtonIcon all_button_icons[] = { |
| views::CAPTION_BUTTON_ICON_MINIMIZE, |
| views::CAPTION_BUTTON_ICON_MAXIMIZE_RESTORE, |
| views::CAPTION_BUTTON_ICON_CLOSE, |
| views::CAPTION_BUTTON_ICON_LEFT_SNAPPED, |
| views::CAPTION_BUTTON_ICON_RIGHT_SNAPPED, |
| views::CAPTION_BUTTON_ICON_BACK, |
| views::CAPTION_BUTTON_ICON_LOCATION, |
| views::CAPTION_BUTTON_ICON_MENU, |
| views::CAPTION_BUTTON_ICON_ZOOM}; |
| |
| for (const auto button : all_button_icons) { |
| if (button_model->IsEnabled(button)) |
| caption_button_enabled_status |= (1 << button); |
| if (button_model->IsVisible(button)) |
| caption_button_visible_status |= (1 << button); |
| } |
| window_info.caption_button_enabled_status = caption_button_enabled_status; |
| window_info.caption_button_visible_status = caption_button_visible_status; |
| } else { |
| auto* widget = views::Widget::GetWidgetForNativeWindow(window); |
| // All widgets for app windows in chromeos should have a frame with |
| // immersive controller. Non app windows may not have a frame and |
| // frame mode will be NONE. |
| DCHECK(!widget || widget->GetNativeWindow()->GetType() != |
| aura::client::WINDOW_TYPE_NORMAL); |
| window_info.frame_mode = |
| api::autotest_private::FrameMode::FRAME_MODE_NONE; |
| window_info.is_frame_visible = false; |
| } |
| |
| // Overview info. |
| if (overview_info.has_value()) { |
| auto it = overview_info->find(window); |
| if (it != overview_info->end()) { |
| window_info.overview_info = |
| std::make_unique<api::autotest_private::OverviewInfo>(); |
| window_info.overview_info->bounds = |
| ToBoundsDictionary(it->second.bounds_in_screen); |
| window_info.overview_info->is_dragged = it->second.is_dragged; |
| } |
| } |
| |
| result_list.emplace_back(std::move(window_info)); |
| } |
| return RespondNow(ArgumentList( |
| api::autotest_private::GetAppWindowList::Results::Create(result_list))); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateSetAppWindowStateFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateSetAppWindowStateFunction:: |
| AutotestPrivateSetAppWindowStateFunction() = default; |
| AutotestPrivateSetAppWindowStateFunction:: |
| ~AutotestPrivateSetAppWindowStateFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| AutotestPrivateSetAppWindowStateFunction::Run() { |
| std::unique_ptr<api::autotest_private::SetAppWindowState::Params> params( |
| api::autotest_private::SetAppWindowState::Params::Create(*args_)); |
| EXTENSION_FUNCTION_VALIDATE(params); |
| DVLOG(1) << "AutotestPrivateSetAppWindowStateFunction " << params->id; |
| |
| aura::Window* window = FindAppWindowById(params->id); |
| if (!window) { |
| return RespondNow(Error( |
| base::StringPrintf("No app window was found : id=%d", params->id))); |
| } |
| |
| chromeos::WindowStateType expected_state = |
| GetExpectedWindowState(params->change.event_type); |
| if (window->GetProperty(chromeos::kWindowStateTypeKey) == expected_state) { |
| if (params->change.fail_if_no_change && |
| *(params->change.fail_if_no_change)) { |
| return RespondNow( |
| Error("The app window was already in the expected window state! ")); |
| } else { |
| return RespondNow(OneArgument(base::Value( |
| api::autotest_private::ToString(ToWindowStateType(expected_state))))); |
| } |
| } |
| |
| window_state_observer_ = std::make_unique<WindowStateChangeObserver>( |
| window, expected_state, |
| base::BindOnce( |
| &AutotestPrivateSetAppWindowStateFunction::WindowStateChanged, this, |
| expected_state)); |
| |
| // TODO(crbug.com/990713): Make WMEvent trigger split view in tablet mode. |
| if (ash::TabletMode::Get()->InTabletMode()) { |
| if (expected_state == chromeos::WindowStateType::kPrimarySnapped) { |
| ash::SplitViewTestApi().SnapWindow( |
| window, ash::SplitViewTestApi::SnapPosition::LEFT); |
| return RespondLater(); |
| } else if (expected_state == chromeos::WindowStateType::kSecondarySnapped) { |
| ash::SplitViewTestApi().SnapWindow( |
| window, ash::SplitViewTestApi::SnapPosition::RIGHT); |
| return RespondLater(); |
| } |
| } |
| |
| const ash::WMEvent event(ToWMEventType(params->change.event_type)); |
| ash::WindowState::Get(window)->OnWMEvent(&event); |
| |
| return RespondLater(); |
| } |
| |
| void AutotestPrivateSetAppWindowStateFunction::WindowStateChanged( |
| chromeos::WindowStateType expected_type, |
| bool success) { |
| if (!success) { |
| Respond(Error( |
| "The app window was destroyed while waiting for its state change! ")); |
| } else { |
| Respond(OneArgument(base::Value( |
| api::autotest_private::ToString(ToWindowStateType(expected_type))))); |
| } |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateActivateAppWindowFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateActivateAppWindowFunction:: |
| ~AutotestPrivateActivateAppWindowFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| AutotestPrivateActivateAppWindowFunction::Run() { |
| std::unique_ptr<api::autotest_private::ActivateAppWindow::Params> params( |
| api::autotest_private::ActivateAppWindow::Params::Create(*args_)); |
| EXTENSION_FUNCTION_VALIDATE(params); |
| DVLOG(1) << "AutotestPrivateActivateAppWindowFunction " << params->id; |
| |
| auto* window = FindAppWindowById(params->id); |
| if (!window) { |
| return RespondNow(Error( |
| base::StringPrintf("No app window was found : id=%d", params->id))); |
| } |
| ash::WindowState::Get(window)->Activate(); |
| |
| return RespondNow(NoArguments()); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateCloseAppWindowFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateCloseAppWindowFunction:: |
| ~AutotestPrivateCloseAppWindowFunction() = default; |
| |
| ExtensionFunction::ResponseAction AutotestPrivateCloseAppWindowFunction::Run() { |
| std::unique_ptr<api::autotest_private::CloseAppWindow::Params> params( |
| api::autotest_private::CloseAppWindow::Params::Create(*args_)); |
| EXTENSION_FUNCTION_VALIDATE(params); |
| DVLOG(1) << "AutotestPrivateCloseAppWindowFunction " << params->id; |
| |
| auto* window = FindAppWindowById(params->id); |
| if (!window) { |
| return RespondNow(Error( |
| base::StringPrintf("No app window was found : id=%d", params->id))); |
| } |
| auto* widget = views::Widget::GetWidgetForNativeWindow(window); |
| widget->Close(); |
| return RespondNow(NoArguments()); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateInstallPWAForCurrentURL |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| // Used to notify when when a certain URL contains a WPA. |
| class AutotestPrivateInstallPWAForCurrentURLFunction::PWABannerObserver |
| : public webapps::AppBannerManager::Observer { |
| public: |
| PWABannerObserver(webapps::AppBannerManager* manager, |
| base::OnceCallback<void()> callback) |
| : callback_(std::move(callback)), app_banner_manager_(manager) { |
| DCHECK(manager); |
| observation_.Observe(manager); |
| |
| // If PWA is already loaded, call callback immediately. |
| Installable installable = |
| app_banner_manager_->GetInstallableWebAppCheckResultForTesting(); |
| if (installable == Installable::kPromotable || |
| installable == Installable::kByUserRequest) { |
| observation_.Reset(); |
| std::move(callback_).Run(); |
| } |
| } |
| ~PWABannerObserver() override {} |
| |
| void OnInstallableWebAppStatusUpdated() override { |
| Installable installable = |
| app_banner_manager_->GetInstallableWebAppCheckResultForTesting(); |
| switch (installable) { |
| case Installable::kNo: |
| FALLTHROUGH; |
| case Installable::kNoAlreadyInstalled: |
| FALLTHROUGH; |
| case Installable::kUnknown: |
| DCHECK(false) << "Unexpected AppBannerManager::Installable value (kNo " |
| "or kNoAlreadyInstalled or kUnknown)"; |
| break; |
| |
| case Installable::kPromotable: |
| FALLTHROUGH; |
| case Installable::kByUserRequest: |
| observation_.Reset(); |
| std::move(callback_).Run(); |
| break; |
| } |
| } |
| |
| private: |
| using Installable = webapps::AppBannerManager::InstallableWebAppCheckResult; |
| |
| base::ScopedObservation<webapps::AppBannerManager, |
| webapps::AppBannerManager::Observer> |
| observation_{this}; |
| base::OnceCallback<void()> callback_; |
| webapps::AppBannerManager* app_banner_manager_; |
| |
| DISALLOW_COPY_AND_ASSIGN(PWABannerObserver); |
| }; |
| |
| // Used to notify when a WPA is installed. |
| class AutotestPrivateInstallPWAForCurrentURLFunction::PWARegistrarObserver |
| : public web_app::AppRegistrarObserver { |
| public: |
| PWARegistrarObserver(Profile* profile, |
| base::OnceCallback<void(const web_app::AppId&)> callback) |
| : callback_(std::move(callback)) { |
| observation_.Observe( |
| &web_app::WebAppProviderBase::GetProviderBase(profile)->registrar()); |
| } |
| ~PWARegistrarObserver() override {} |
| |
| void OnWebAppInstalled(const web_app::AppId& app_id) override { |
| observation_.Reset(); |
| std::move(callback_).Run(app_id); |
| } |
| |
| private: |
| base::ScopedObservation<web_app::AppRegistrar, web_app::AppRegistrarObserver> |
| observation_{this}; |
| base::OnceCallback<void(const web_app::AppId&)> callback_; |
| |
| DISALLOW_COPY_AND_ASSIGN(PWARegistrarObserver); |
| }; |
| |
| AutotestPrivateInstallPWAForCurrentURLFunction:: |
| AutotestPrivateInstallPWAForCurrentURLFunction() = default; |
| AutotestPrivateInstallPWAForCurrentURLFunction:: |
| ~AutotestPrivateInstallPWAForCurrentURLFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| AutotestPrivateInstallPWAForCurrentURLFunction::Run() { |
| DVLOG(1) << "AutotestPrivateInstallPWAForCurrentURLFunction"; |
| |
| std::unique_ptr<api::autotest_private::InstallPWAForCurrentURL::Params> |
| params(api::autotest_private::InstallPWAForCurrentURL::Params::Create( |
| *args_)); |
| EXTENSION_FUNCTION_VALIDATE(params); |
| |
| Browser* browser = GetFirstRegularBrowser(); |
| if (!browser) { |
| return RespondNow(Error("Failed to find regular browser")); |
| } |
| content::WebContents* web_contents = |
| browser->tab_strip_model()->GetActiveWebContents(); |
| |
| webapps::AppBannerManager* app_banner_manager = |
| webapps::AppBannerManagerDesktop::FromWebContents(web_contents); |
| if (!app_banner_manager) { |
| return RespondNow(Error("Failed to create AppBannerManager")); |
| } |
| |
| banner_observer_ = std::make_unique<PWABannerObserver>( |
| app_banner_manager, |
| base::BindOnce(&AutotestPrivateInstallPWAForCurrentURLFunction::PWALoaded, |
| this)); |
| |
| // Adding timeout to catch: |
| // - There is no way to know whether ExecuteCommand fails. |
| // - Current URL might not have a valid PWA. |
| timeout_timer_.Start( |
| FROM_HERE, base::TimeDelta::FromMilliseconds(params->timeout_ms), |
| base::BindOnce( |
| &AutotestPrivateInstallPWAForCurrentURLFunction::PWATimeout, this)); |
| return RespondLater(); |
| } |
| |
| void AutotestPrivateInstallPWAForCurrentURLFunction::PWALoaded() { |
| Profile* profile = Profile::FromBrowserContext(browser_context()); |
| Browser* browser = GetFirstRegularBrowser(); |
| |
| registrar_observer_ = std::make_unique<PWARegistrarObserver>( |
| profile, |
| base::BindOnce( |
| &AutotestPrivateInstallPWAForCurrentURLFunction::PWAInstalled, this)); |
| |
| chrome::SetAutoAcceptPWAInstallConfirmationForTesting(true); |
| if (!chrome::ExecuteCommand(browser, IDC_INSTALL_PWA)) { |
| return Respond(Error("Failed to execute INSTALL_PWA command")); |
| } |
| } |
| |
| void AutotestPrivateInstallPWAForCurrentURLFunction::PWAInstalled( |
| const web_app::AppId& app_id) { |
| chrome::SetAutoAcceptPWAInstallConfirmationForTesting(false); |
| Respond(OneArgument(base::Value(app_id))); |
| timeout_timer_.AbandonAndStop(); |
| } |
| |
| void AutotestPrivateInstallPWAForCurrentURLFunction::PWATimeout() { |
| chrome::SetAutoAcceptPWAInstallConfirmationForTesting(false); |
| Respond(Error("Install PWA timed out")); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateActivateAcceleratorFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateActivateAcceleratorFunction:: |
| AutotestPrivateActivateAcceleratorFunction() = default; |
| AutotestPrivateActivateAcceleratorFunction:: |
| ~AutotestPrivateActivateAcceleratorFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| AutotestPrivateActivateAcceleratorFunction::Run() { |
| std::unique_ptr<api::autotest_private::ActivateAccelerator::Params> params( |
| api::autotest_private::ActivateAccelerator::Params::Create(*args_)); |
| EXTENSION_FUNCTION_VALIDATE(params); |
| |
| int modifiers = (params->accelerator.control ? ui::EF_CONTROL_DOWN : 0) | |
| (params->accelerator.shift ? ui::EF_SHIFT_DOWN : 0) | |
| (params->accelerator.alt ? ui::EF_ALT_DOWN : 0) | |
| (params->accelerator.search ? ui::EF_COMMAND_DOWN : 0); |
| ui::Accelerator accelerator( |
| StringToKeyCode(params->accelerator.key_code), modifiers, |
| params->accelerator.pressed ? ui::Accelerator::KeyState::PRESSED |
| : ui::Accelerator::KeyState::RELEASED); |
| auto* accelerator_controller = ash::AcceleratorController::Get(); |
| accelerator_controller->GetAcceleratorHistory()->StoreCurrentAccelerator( |
| accelerator); |
| |
| if (!accelerator_controller->IsRegistered(accelerator)) { |
| // If it's not ash accelerator, try aplication's accelerator. |
| auto* window = GetActiveWindow(); |
| if (!window) { |
| return RespondNow( |
| Error(base::StringPrintf("Accelerator is not registered 1"))); |
| } |
| auto* widget = views::Widget::GetWidgetForNativeWindow(window); |
| if (!widget) { |
| return RespondNow( |
| Error(base::StringPrintf("Accelerator is not registered 2"))); |
| } |
| bool result = widget->GetFocusManager()->ProcessAccelerator(accelerator); |
| return RespondNow(OneArgument(base::Value(result))); |
| } |
| bool result = accelerator_controller->Process(accelerator); |
| return RespondNow(OneArgument(base::Value(result))); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateWaitForLauncherStateFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateWaitForLauncherStateFunction:: |
| AutotestPrivateWaitForLauncherStateFunction() = default; |
| AutotestPrivateWaitForLauncherStateFunction:: |
| ~AutotestPrivateWaitForLauncherStateFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| AutotestPrivateWaitForLauncherStateFunction::Run() { |
| std::unique_ptr<api::autotest_private::WaitForLauncherState::Params> params( |
| api::autotest_private::WaitForLauncherState::Params::Create(*args_)); |
| EXTENSION_FUNCTION_VALIDATE(params); |
| auto target_state = ToAppListViewState(params->launcher_state); |
| if (WaitForLauncherState( |
| target_state, |
| base::BindOnce(&AutotestPrivateWaitForLauncherStateFunction::Done, |
| this))) { |
| return AlreadyResponded(); |
| } |
| return RespondLater(); |
| } |
| |
| void AutotestPrivateWaitForLauncherStateFunction::Done() { |
| Respond(NoArguments()); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateCreateNewDeskFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateCreateNewDeskFunction::AutotestPrivateCreateNewDeskFunction() = |
| default; |
| AutotestPrivateCreateNewDeskFunction::~AutotestPrivateCreateNewDeskFunction() = |
| default; |
| |
| ExtensionFunction::ResponseAction AutotestPrivateCreateNewDeskFunction::Run() { |
| const bool success = ash::AutotestDesksApi().CreateNewDesk(); |
| return RespondNow(OneArgument(base::Value(success))); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateActivateDeskAtIndexFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateActivateDeskAtIndexFunction:: |
| AutotestPrivateActivateDeskAtIndexFunction() = default; |
| AutotestPrivateActivateDeskAtIndexFunction:: |
| ~AutotestPrivateActivateDeskAtIndexFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| AutotestPrivateActivateDeskAtIndexFunction::Run() { |
| std::unique_ptr<api::autotest_private::ActivateDeskAtIndex::Params> params( |
| api::autotest_private::ActivateDeskAtIndex::Params::Create(*args_)); |
| EXTENSION_FUNCTION_VALIDATE(params); |
| |
| if (!ash::AutotestDesksApi().ActivateDeskAtIndex( |
| params->index, |
| base::BindOnce( |
| &AutotestPrivateActivateDeskAtIndexFunction::OnAnimationComplete, |
| this))) { |
| return RespondNow(OneArgument(base::Value(false))); |
| } |
| |
| return RespondLater(); |
| } |
| |
| void AutotestPrivateActivateDeskAtIndexFunction::OnAnimationComplete() { |
| Respond(OneArgument(base::Value(true))); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateRemoveActiveDeskFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateRemoveActiveDeskFunction:: |
| AutotestPrivateRemoveActiveDeskFunction() = default; |
| AutotestPrivateRemoveActiveDeskFunction:: |
| ~AutotestPrivateRemoveActiveDeskFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| AutotestPrivateRemoveActiveDeskFunction::Run() { |
| if (!ash::AutotestDesksApi().RemoveActiveDesk(base::BindOnce( |
| &AutotestPrivateRemoveActiveDeskFunction::OnAnimationComplete, |
| this))) { |
| return RespondNow(OneArgument(base::Value(false))); |
| } |
| |
| return RespondLater(); |
| } |
| |
| void AutotestPrivateRemoveActiveDeskFunction::OnAnimationComplete() { |
| Respond(OneArgument(base::Value(true))); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateActivateAdjacentDesksToTargetIndexFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateActivateAdjacentDesksToTargetIndexFunction:: |
| AutotestPrivateActivateAdjacentDesksToTargetIndexFunction() = default; |
| AutotestPrivateActivateAdjacentDesksToTargetIndexFunction:: |
| ~AutotestPrivateActivateAdjacentDesksToTargetIndexFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| AutotestPrivateActivateAdjacentDesksToTargetIndexFunction::Run() { |
| std::unique_ptr< |
| api::autotest_private::ActivateAdjacentDesksToTargetIndex::Params> |
| params(api::autotest_private::ActivateAdjacentDesksToTargetIndex::Params:: |
| Create(*args_)); |
| EXTENSION_FUNCTION_VALIDATE(params); |
| |
| if (!ash::AutotestDesksApi().ActivateAdjacentDesksToTargetIndex( |
| params->index, |
| base::BindOnce( |
| &AutotestPrivateActivateAdjacentDesksToTargetIndexFunction:: |
| OnAnimationComplete, |
| this))) { |
| return RespondNow(OneArgument(base::Value(false))); |
| } |
| |
| return RespondLater(); |
| } |
| |
| void AutotestPrivateActivateAdjacentDesksToTargetIndexFunction:: |
| OnAnimationComplete() { |
| Respond(OneArgument(base::Value(true))); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateMouseClickFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateMouseClickFunction::AutotestPrivateMouseClickFunction() = |
| default; |
| |
| AutotestPrivateMouseClickFunction::~AutotestPrivateMouseClickFunction() = |
| default; |
| |
| ExtensionFunction::ResponseAction AutotestPrivateMouseClickFunction::Run() { |
| std::unique_ptr<api::autotest_private::MouseClick::Params> params( |
| api::autotest_private::MouseClick::Params::Create(*args_)); |
| EXTENSION_FUNCTION_VALIDATE(params); |
| |
| auto* env = aura::Env::GetInstance(); |
| if (env->mouse_button_flags() != 0) { |
| return RespondNow(Error(base::StringPrintf("Already pressed; flags %d", |
| env->mouse_button_flags()))); |
| } |
| |
| int64_t display_id = ash::Shell::Get()->cursor_manager()->GetDisplay().id(); |
| auto* root_window = ash::Shell::GetRootWindowForDisplayId(display_id); |
| if (!root_window) |
| return RespondNow(Error("Failed to find the root window")); |
| |
| gfx::PointF location_in_host(env->last_mouse_location().x(), |
| env->last_mouse_location().y()); |
| wm::ConvertPointFromScreen(root_window, &location_in_host); |
| ConvertPointToHost(root_window, &location_in_host); |
| |
| int flags = GetMouseEventFlags(params->button); |
| event_generator_ = std::make_unique<EventGenerator>( |
| root_window->GetHost(), |
| base::BindOnce(&AutotestPrivateMouseClickFunction::Respond, this, |
| NoArguments())); |
| event_generator_->ScheduleMouseEvent(ui::ET_MOUSE_PRESSED, location_in_host, |
| flags); |
| event_generator_->ScheduleMouseEvent(ui::ET_MOUSE_RELEASED, location_in_host, |
| flags); |
| event_generator_->Run(); |
| |
| return RespondLater(); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateMousePressFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateMousePressFunction::AutotestPrivateMousePressFunction() = |
| default; |
| AutotestPrivateMousePressFunction::~AutotestPrivateMousePressFunction() = |
| default; |
| |
| ExtensionFunction::ResponseAction AutotestPrivateMousePressFunction::Run() { |
| std::unique_ptr<api::autotest_private::MousePress::Params> params( |
| api::autotest_private::MousePress::Params::Create(*args_)); |
| EXTENSION_FUNCTION_VALIDATE(params); |
| |
| auto* env = aura::Env::GetInstance(); |
| int input_flags = GetMouseEventFlags(params->button); |
| if ((input_flags | env->mouse_button_flags()) == env->mouse_button_flags()) |
| return RespondNow(NoArguments()); |
| |
| int64_t display_id = ash::Shell::Get()->cursor_manager()->GetDisplay().id(); |
| auto* root_window = ash::Shell::GetRootWindowForDisplayId(display_id); |
| if (!root_window) |
| return RespondNow(Error("Failed to find the root window")); |
| |
| gfx::PointF location_in_host(env->last_mouse_location().x(), |
| env->last_mouse_location().y()); |
| wm::ConvertPointFromScreen(root_window, &location_in_host); |
| ConvertPointToHost(root_window, &location_in_host); |
| |
| event_generator_ = std::make_unique<EventGenerator>( |
| root_window->GetHost(), |
| base::BindOnce(&AutotestPrivateMousePressFunction::Respond, this, |
| NoArguments())); |
| event_generator_->ScheduleMouseEvent(ui::ET_MOUSE_PRESSED, location_in_host, |
| input_flags); |
| event_generator_->Run(); |
| |
| return RespondLater(); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateMouseReleaseFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateMouseReleaseFunction::AutotestPrivateMouseReleaseFunction() = |
| default; |
| AutotestPrivateMouseReleaseFunction::~AutotestPrivateMouseReleaseFunction() = |
| default; |
| |
| ExtensionFunction::ResponseAction AutotestPrivateMouseReleaseFunction::Run() { |
| std::unique_ptr<api::autotest_private::MouseRelease::Params> params( |
| api::autotest_private::MouseRelease::Params::Create(*args_)); |
| EXTENSION_FUNCTION_VALIDATE(params); |
| |
| auto* env = aura::Env::GetInstance(); |
| |
| int input_flags = GetMouseEventFlags(params->button); |
| if ((env->mouse_button_flags() & (~input_flags)) == env->mouse_button_flags()) |
| return RespondNow(NoArguments()); |
| |
| int64_t display_id = ash::Shell::Get()->cursor_manager()->GetDisplay().id(); |
| auto* root_window = ash::Shell::GetRootWindowForDisplayId(display_id); |
| if (!root_window) |
| return RespondNow(Error("Failed to find the root window")); |
| |
| gfx::PointF location_in_host(env->last_mouse_location().x(), |
| env->last_mouse_location().y()); |
| wm::ConvertPointFromScreen(root_window, &location_in_host); |
| ConvertPointToHost(root_window, &location_in_host); |
| |
| event_generator_ = std::make_unique<EventGenerator>( |
| root_window->GetHost(), |
| base::BindOnce(&AutotestPrivateMouseReleaseFunction::Respond, this, |
| NoArguments())); |
| event_generator_->ScheduleMouseEvent(ui::ET_MOUSE_RELEASED, location_in_host, |
| input_flags); |
| event_generator_->Run(); |
| |
| return RespondLater(); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateMouseMoveFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateMouseMoveFunction::AutotestPrivateMouseMoveFunction() = default; |
| AutotestPrivateMouseMoveFunction::~AutotestPrivateMouseMoveFunction() = default; |
| ExtensionFunction::ResponseAction AutotestPrivateMouseMoveFunction::Run() { |
| std::unique_ptr<api::autotest_private::MouseMove::Params> params( |
| api::autotest_private::MouseMove::Params::Create(*args_)); |
| EXTENSION_FUNCTION_VALIDATE(params); |
| |
| int64_t display_id = ash::Shell::Get()->cursor_manager()->GetDisplay().id(); |
| auto* root_window = ash::Shell::GetRootWindowForDisplayId(display_id); |
| if (!root_window) |
| return RespondNow(Error("Failed to find the root window")); |
| |
| gfx::Point location_in_screen(params->location.x, params->location.y); |
| auto* env = aura::Env::GetInstance(); |
| const gfx::Point last_mouse_location(env->last_mouse_location()); |
| if (last_mouse_location == location_in_screen) |
| return RespondNow(NoArguments()); |
| |
| event_generator_ = std::make_unique<EventGenerator>( |
| root_window->GetHost(), |
| base::BindOnce(&AutotestPrivateMouseMoveFunction::Respond, this, |
| NoArguments())); |
| |
| int64_t steps = std::max( |
| base::ClampFloor<int64_t>(params->duration_in_ms / |
| event_generator_->interval().InMillisecondsF()), |
| static_cast<int64_t>(1)); |
| int flags = env->mouse_button_flags(); |
| for (int64_t i = 1; i <= steps; ++i) { |
| double progress = static_cast<double>(i) / static_cast<double>(steps); |
| gfx::PointF point( |
| gfx::Tween::FloatValueBetween(progress, last_mouse_location.x(), |
| location_in_screen.x()), |
| gfx::Tween::FloatValueBetween(progress, last_mouse_location.y(), |
| location_in_screen.y())); |
| event_generator_->ScheduleMouseEvent(ui::ET_MOUSE_MOVED, point, flags); |
| } |
| event_generator_->Run(); |
| return RespondLater(); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateSetMetricsEnabledFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateSetMetricsEnabledFunction:: |
| AutotestPrivateSetMetricsEnabledFunction() = default; |
| |
| AutotestPrivateSetMetricsEnabledFunction:: |
| ~AutotestPrivateSetMetricsEnabledFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| AutotestPrivateSetMetricsEnabledFunction::Run() { |
| std::unique_ptr<api::autotest_private::SetMetricsEnabled::Params> params( |
| api::autotest_private::SetMetricsEnabled::Params::Create(*args_)); |
| EXTENSION_FUNCTION_VALIDATE(params); |
| VLOG(1) << "AutotestPrivateSetMetricsEnabledFunction " << std::boolalpha |
| << params->enabled; |
| |
| target_value_ = params->enabled; |
| |
| Profile* profile = Profile::FromBrowserContext(browser_context()); |
| |
| bool value; |
| if (ash::CrosSettings::Get()->GetBoolean(chromeos::kStatsReportingPref, |
| &value) && |
| value == target_value_) { |
| VLOG(1) << "Value at target; returning early"; |
| return RespondNow(NoArguments()); |
| } |
| |
| ash::StatsReportingController* stats_reporting_controller = |
| ash::StatsReportingController::Get(); |
| |
| stats_reporting_controller->SetOnDeviceSettingsStoredCallBack(base::BindOnce( |
| &AutotestPrivateSetMetricsEnabledFunction::OnDeviceSettingsStored, this)); |
| |
| // Set the preference to indicate metrics are enabled/disabled. |
| stats_reporting_controller->SetEnabled(profile, target_value_); |
| |
| return RespondLater(); |
| } |
| |
| void AutotestPrivateSetMetricsEnabledFunction::OnDeviceSettingsStored() { |
| bool actual; |
| if (!ash::CrosSettings::Get()->GetBoolean(chromeos::kStatsReportingPref, |
| &actual)) { |
| NOTREACHED() << "AutotestPrivateSetMetricsEnabledFunction: " |
| << "kStatsReportingPref should be set"; |
| Respond(Error(base::StrCat( |
| {"Failed to set metrics consent: ", chromeos::kStatsReportingPref, |
| " is not set."}))); |
| return; |
| } |
| VLOG(1) << "AutotestPrivateSetMetricsEnabledFunction: actual: " |
| << std::boolalpha << actual << " and expected: " << std::boolalpha |
| << target_value_; |
| if (actual == target_value_) { |
| Respond(NoArguments()); |
| } else { |
| Respond(Error(base::StrCat( |
| {"Failed to set metrics consent: ", chromeos::kStatsReportingPref, |
| " has wrong value."}))); |
| } |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateStartTracingFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| AutotestPrivateStartTracingFunction::AutotestPrivateStartTracingFunction() = |
| default; |
| AutotestPrivateStartTracingFunction::~AutotestPrivateStartTracingFunction() = |
| default; |
| |
| ExtensionFunction::ResponseAction AutotestPrivateStartTracingFunction::Run() { |
| std::unique_ptr<api::autotest_private::StartTracing::Params> params( |
| api::autotest_private::StartTracing::Params::Create(*args_)); |
| EXTENSION_FUNCTION_VALIDATE(params); |
| std::unique_ptr<base::Value> config_value = params->config.ToValue(); |
| base::trace_event::TraceConfig config(*config_value.get()); |
| |
| if (!content::TracingController::GetInstance()->StartTracing( |
| config, |
| base::BindOnce(&AutotestPrivateStartTracingFunction::OnStartTracing, |
| this))) { |
| return RespondNow(Error("Failed to start tracing")); |
| } |
| |
| return RespondLater(); |
| } |
| |
| void AutotestPrivateStartTracingFunction::OnStartTracing() { |
| Respond(NoArguments()); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateStopTracingFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| AutotestPrivateStopTracingFunction::AutotestPrivateStopTracingFunction() = |
| default; |
| AutotestPrivateStopTracingFunction::~AutotestPrivateStopTracingFunction() = |
| default; |
| |
| ExtensionFunction::ResponseAction AutotestPrivateStopTracingFunction::Run() { |
| if (!content::TracingController::GetInstance()->StopTracing( |
| content::TracingController::CreateStringEndpoint(base::BindOnce( |
| &AutotestPrivateStopTracingFunction::OnTracingComplete, this)))) { |
| return RespondNow(Error("Failed to stop tracing")); |
| } |
| return RespondLater(); |
| } |
| |
| void AutotestPrivateStopTracingFunction::OnTracingComplete( |
| std::unique_ptr<std::string> trace) { |
| base::Value value(*trace.get()); |
| Respond(OneArgument(std::move(value))); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateSetArcTouchModeFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| AutotestPrivateSetArcTouchModeFunction:: |
| AutotestPrivateSetArcTouchModeFunction() = default; |
| AutotestPrivateSetArcTouchModeFunction:: |
| ~AutotestPrivateSetArcTouchModeFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| AutotestPrivateSetArcTouchModeFunction::Run() { |
| std::unique_ptr<api::autotest_private::SetArcTouchMode::Params> params( |
| api::autotest_private::SetArcTouchMode::Params::Create(*args_)); |
| EXTENSION_FUNCTION_VALIDATE(params); |
| DVLOG(1) << "AutotestPrivateSetArcTouchModeFunction " << params->enabled; |
| |
| if (!arc::SetTouchMode(params->enabled)) |
| return RespondNow(Error("Could not send intent to ARC.")); |
| |
| return RespondNow(NoArguments()); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivatePinShelfIconFunction |
| //////////////////////////////////////////////////////////////////////////////// |
| AutotestPrivatePinShelfIconFunction::AutotestPrivatePinShelfIconFunction() = |
| default; |
| AutotestPrivatePinShelfIconFunction::~AutotestPrivatePinShelfIconFunction() = |
| default; |
| |
| ExtensionFunction::ResponseAction AutotestPrivatePinShelfIconFunction::Run() { |
| std::unique_ptr<api::autotest_private::PinShelfIcon::Params> params( |
| api::autotest_private::PinShelfIcon::Params::Create(*args_)); |
| EXTENSION_FUNCTION_VALIDATE(params); |
| DVLOG(1) << "AutotestPrivatePinShelfIconFunction " << params->app_id; |
| |
| ChromeShelfController* const controller = ChromeShelfController::instance(); |
| if (!controller) |
| return RespondNow(Error("Controller not available")); |
| |
| controller->PinAppWithID(params->app_id); |
| return RespondNow(NoArguments()); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateGetScrollableShelfInfoForStateFunction |
| //////////////////////////////////////////////////////////////////////////////// |
| AutotestPrivateGetScrollableShelfInfoForStateFunction:: |
| AutotestPrivateGetScrollableShelfInfoForStateFunction() = default; |
| AutotestPrivateGetScrollableShelfInfoForStateFunction:: |
| ~AutotestPrivateGetScrollableShelfInfoForStateFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| AutotestPrivateGetScrollableShelfInfoForStateFunction::Run() { |
| DVLOG(1) << "AutotestPrivateGetScrollableShelfInfoForStateFunction"; |
| std::unique_ptr<api::autotest_private::GetScrollableShelfInfoForState::Params> |
| params( |
| api::autotest_private::GetScrollableShelfInfoForState::Params::Create( |
| *args_)); |
| |
| ash::ShelfTestApi shelf_test_api; |
| |
| ash::ShelfState state; |
| |
| if (params->state.scroll_distance) |
| state.scroll_distance = *params->state.scroll_distance; |
| |
| ash::ScrollableShelfInfo fetched_info = |
| shelf_test_api.GetScrollableShelfInfoForState(state); |
| |
| api::autotest_private::ScrollableShelfInfo info; |
| info.main_axis_offset = fetched_info.main_axis_offset; |
| info.page_offset = fetched_info.page_offset; |
| info.left_arrow_bounds = ToBoundsDictionary(fetched_info.left_arrow_bounds); |
| info.right_arrow_bounds = ToBoundsDictionary(fetched_info.right_arrow_bounds); |
| info.is_animating = fetched_info.is_animating; |
| info.is_overflow = fetched_info.is_overflow; |
| |
| if (params->state.scroll_distance) { |
| info.target_main_axis_offset = |
| std::make_unique<double>(fetched_info.target_main_axis_offset); |
| } |
| |
| return RespondNow( |
| OneArgument(base::Value::FromUniquePtrValue(info.ToValue()))); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateGetShelfUIInfoForStateFunction |
| //////////////////////////////////////////////////////////////////////////////// |
| AutotestPrivateGetShelfUIInfoForStateFunction:: |
| AutotestPrivateGetShelfUIInfoForStateFunction() = default; |
| AutotestPrivateGetShelfUIInfoForStateFunction:: |
| ~AutotestPrivateGetShelfUIInfoForStateFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| AutotestPrivateGetShelfUIInfoForStateFunction::Run() { |
| DVLOG(1) << "AutotestPrivateGetShelfUIInfoForStateFunction"; |
| std::unique_ptr<api::autotest_private::GetShelfUIInfoForState::Params> params( |
| api::autotest_private::GetShelfUIInfoForState::Params::Create(*args_)); |
| |
| ash::ShelfState state; |
| if (params->state.scroll_distance) |
| state.scroll_distance = *params->state.scroll_distance; |
| |
| api::autotest_private::ShelfUIInfo shelf_ui_info; |
| ash::ShelfTestApi shelf_test_api; |
| |
| // Fetch scrollable shelf ui information. |
| { |
| ash::ScrollableShelfInfo fetched_info = |
| shelf_test_api.GetScrollableShelfInfoForState(state); |
| |
| api::autotest_private::ScrollableShelfInfo scrollable_shelf_ui_info; |
| scrollable_shelf_ui_info.main_axis_offset = fetched_info.main_axis_offset; |
| scrollable_shelf_ui_info.page_offset = fetched_info.page_offset; |
| scrollable_shelf_ui_info.left_arrow_bounds = |
| ToBoundsDictionary(fetched_info.left_arrow_bounds); |
| scrollable_shelf_ui_info.right_arrow_bounds = |
| ToBoundsDictionary(fetched_info.right_arrow_bounds); |
| scrollable_shelf_ui_info.is_animating = fetched_info.is_animating; |
| scrollable_shelf_ui_info.icons_under_animation = |
| fetched_info.icons_under_animation; |
| scrollable_shelf_ui_info.is_overflow = fetched_info.is_overflow; |
| scrollable_shelf_ui_info.icons_bounds_in_screen = |
| ToBoundsDictionaryList(fetched_info.icons_bounds_in_screen); |
| scrollable_shelf_ui_info.is_shelf_widget_animating = |
| fetched_info.is_shelf_widget_animating; |
| |
| if (state.scroll_distance) { |
| scrollable_shelf_ui_info.target_main_axis_offset = |
| std::make_unique<double>(fetched_info.target_main_axis_offset); |
| } |
| |
| shelf_ui_info.scrollable_shelf_info = std::move(scrollable_shelf_ui_info); |
| } |
| |
| // Fetch hotseat ui information. |
| { |
| ash::HotseatInfo hotseat_info = shelf_test_api.GetHotseatInfo(); |
| api::autotest_private::HotseatSwipeDescriptor swipe_up_descriptor; |
| swipe_up_descriptor.swipe_start_location = |
| ToLocationDictionary(hotseat_info.swipe_up.swipe_start_location); |
| swipe_up_descriptor.swipe_end_location = |
| ToLocationDictionary(hotseat_info.swipe_up.swipe_end_location); |
| |
| api::autotest_private::HotseatInfo hotseat_ui_info; |
| hotseat_ui_info.swipe_up = std::move(swipe_up_descriptor); |
| hotseat_ui_info.is_animating = hotseat_info.is_animating; |
| hotseat_ui_info.state = GetHotseatState(hotseat_info.hotseat_state); |
| |
| shelf_ui_info.hotseat_info = std::move(hotseat_ui_info); |
| } |
| |
| return RespondNow( |
| OneArgument(base::Value::FromUniquePtrValue(shelf_ui_info.ToValue()))); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateSetWindowBoundsFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateSetWindowBoundsFunction:: |
| AutotestPrivateSetWindowBoundsFunction() = default; |
| AutotestPrivateSetWindowBoundsFunction:: |
| ~AutotestPrivateSetWindowBoundsFunction() = default; |
| |
| namespace { |
| |
| std::unique_ptr<base::DictionaryValue> BuildSetWindowBoundsResult( |
| const gfx::Rect& bounds_in_display, |
| int64_t display_id) { |
| auto result = std::make_unique<base::DictionaryValue>(); |
| result->SetDictionary("bounds", |
| ToBoundsDictionary(bounds_in_display).ToValue()); |
| result->SetString("displayId", base::NumberToString(display_id)); |
| return result; |
| } |
| |
| } // namespace |
| |
| ExtensionFunction::ResponseAction |
| AutotestPrivateSetWindowBoundsFunction::Run() { |
| std::unique_ptr<api::autotest_private::SetWindowBounds::Params> params( |
| api::autotest_private::SetWindowBounds::Params::Create(*args_)); |
| EXTENSION_FUNCTION_VALIDATE(params); |
| |
| aura::Window* window = FindAppWindowById(params->id); |
| if (!window) { |
| return RespondNow(Error( |
| base::StringPrintf("No app window was found : id=%d", params->id))); |
| } |
| |
| auto* state = ash::WindowState::Get(window); |
| if (!state || chromeos::ToWindowShowState(state->GetStateType()) != |
| ui::SHOW_STATE_NORMAL) { |
| return RespondNow( |
| Error("Cannot set bounds of window not in normal show state.")); |
| } |
| |
| int64_t display_id; |
| if (!base::StringToInt64(params->display_id, &display_id)) { |
| return RespondNow(Error(base::StrCat( |
| {"Invalid display_id; expected string with numbers only, got ", |
| params->display_id}))); |
| } |
| |
| display::Display display; |
| display::Screen::GetScreen()->GetDisplayWithDisplayId(display_id, &display); |
| if (!display.is_valid()) { |
| return RespondNow( |
| Error("Given display ID does not correspond to a valid display")); |
| } |
| |
| auto* root_window = ash::Shell::GetRootWindowForDisplayId(display_id); |
| if (!root_window) |
| return RespondNow(Error("Failed to find the root window")); |
| |
| gfx::Rect to_bounds = ToRect(params->bounds); |
| |
| if (window->GetBoundsInRootWindow() == to_bounds && |
| state->GetDisplay().id() == display_id) { |
| return RespondNow(OneArgument(base::Value::FromUniquePtrValue( |
| BuildSetWindowBoundsResult(to_bounds, display_id)))); |
| } |
| |
| window_bounds_observer_ = std::make_unique<WindowBoundsChangeObserver>( |
| window, to_bounds, display_id, |
| base::BindOnce( |
| &AutotestPrivateSetWindowBoundsFunction::WindowBoundsChanged, this)); |
| |
| ::wm::ConvertRectToScreen(root_window, &to_bounds); |
| window->SetBoundsInScreen(to_bounds, display); |
| |
| return RespondLater(); |
| } |
| |
| void AutotestPrivateSetWindowBoundsFunction::WindowBoundsChanged( |
| const gfx::Rect& bounds_in_display, |
| int64_t display_id, |
| bool success) { |
| if (!success) { |
| Respond(Error( |
| "The app window was destroyed while waiting for bounds to change!")); |
| } else { |
| Respond(OneArgument(base::Value::FromUniquePtrValue( |
| BuildSetWindowBoundsResult(bounds_in_display, display_id)))); |
| } |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateStartSmoothnessTrackingFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateStartSmoothnessTrackingFunction:: |
| ~AutotestPrivateStartSmoothnessTrackingFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| AutotestPrivateStartSmoothnessTrackingFunction::Run() { |
| auto params( |
| api::autotest_private::StartSmoothnessTracking::Params::Create(*args_)); |
| EXTENSION_FUNCTION_VALIDATE(params); |
| |
| int64_t display_id; |
| if (!GetDisplayIdFromOptionalArg(params->display_id, &display_id)) { |
| return RespondNow( |
| Error(base::StrCat({"Invalid display id: ", *params->display_id}))); |
| } |
| |
| auto* infos = GetDisplaySmoothnessTrackerInfos(); |
| if (infos->find(display_id) != infos->end()) { |
| return RespondNow( |
| Error(base::StrCat({"Smoothness already tracked for display: ", |
| base::NumberToString(display_id)}))); |
| } |
| |
| auto* root_window = ash::Shell::GetRootWindowForDisplayId(display_id); |
| if (!root_window) { |
| return RespondNow(Error(base::StrCat( |
| {"Invalid display_id; no root window found for the display id ", |
| base::NumberToString(display_id)}))); |
| } |
| |
| auto tracker = |
| root_window->layer()->GetCompositor()->RequestNewThroughputTracker(); |
| tracker.Start(base::BindOnce(&ForwardFrameRateDataAndReset, display_id)); |
| (*infos)[display_id].tracker = std::move(tracker); |
| return RespondNow(NoArguments()); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateStopSmoothnessTrackingFunction |
| ////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateStopSmoothnessTrackingFunction:: |
| ~AutotestPrivateStopSmoothnessTrackingFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| AutotestPrivateStopSmoothnessTrackingFunction::Run() { |
| auto params( |
| api::autotest_private::StopSmoothnessTracking::Params::Create(*args_)); |
| EXTENSION_FUNCTION_VALIDATE(params); |
| |
| int64_t display_id; |
| if (!GetDisplayIdFromOptionalArg(params->display_id, &display_id)) { |
| return RespondNow( |
| Error(base::StrCat({"Invalid display id: ", *params->display_id}))); |
| } |
| |
| auto* infos = GetDisplaySmoothnessTrackerInfos(); |
| auto it = infos->find(display_id); |
| if (it == infos->end()) { |
| return RespondNow( |
| Error(base::StrCat({"Smoothness is not tracked for display: ", |
| base::NumberToString(display_id)}))); |
| } |
| |
| it->second.callback = base::BindOnce( |
| &AutotestPrivateStopSmoothnessTrackingFunction::OnReportData, this); |
| it->second.tracker->Stop(); |
| |
| return did_respond() ? AlreadyResponded() : RespondLater(); |
| } |
| |
| void AutotestPrivateStopSmoothnessTrackingFunction::OnReportData( |
| const cc::FrameSequenceMetrics::CustomReportData& data) { |
| api::autotest_private::ThroughputTrackerAnimationData result_data; |
| result_data.frames_expected = data.frames_expected; |
| result_data.frames_produced = data.frames_produced; |
| result_data.jank_count = data.jank_count; |
| |
| Respond(ArgumentList( |
| api::autotest_private::StopSmoothnessTracking::Results::Create( |
| result_data))); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateWaitForAmbientPhotoAnimationFunction |
| ////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateWaitForAmbientPhotoAnimationFunction:: |
| AutotestPrivateWaitForAmbientPhotoAnimationFunction() = default; |
| |
| AutotestPrivateWaitForAmbientPhotoAnimationFunction:: |
| ~AutotestPrivateWaitForAmbientPhotoAnimationFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| AutotestPrivateWaitForAmbientPhotoAnimationFunction::Run() { |
| std::unique_ptr<api::autotest_private::WaitForAmbientPhotoAnimation::Params> |
| params( |
| api::autotest_private::WaitForAmbientPhotoAnimation::Params::Create( |
| *args_)); |
| EXTENSION_FUNCTION_VALIDATE(params); |
| |
| // Wait for photo transition animation completed in ambient mode. |
| ash::AutotestAmbientApi().WaitForPhotoTransitionAnimationCompleted( |
| params->num_completions, base::TimeDelta::FromSeconds(params->timeout), |
| /*on_complete=*/ |
| base::BindOnce(&AutotestPrivateWaitForAmbientPhotoAnimationFunction:: |
| OnPhotoTransitionAnimationCompleted, |
| this), |
| /*on_timeout=*/ |
| base::BindOnce( |
| &AutotestPrivateWaitForAmbientPhotoAnimationFunction::Timeout, this)); |
| |
| return did_respond() ? AlreadyResponded() : RespondLater(); |
| } |
| |
| void AutotestPrivateWaitForAmbientPhotoAnimationFunction:: |
| OnPhotoTransitionAnimationCompleted() { |
| if (did_respond()) |
| return; |
| |
| Respond(NoArguments()); |
| } |
| |
| void AutotestPrivateWaitForAmbientPhotoAnimationFunction::Timeout() { |
| if (did_respond()) |
| return; |
| |
| Respond(Error("Not enough animations completed before time out.")); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateDisableSwitchAccessDialogFunction |
| ////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateDisableSwitchAccessDialogFunction:: |
| AutotestPrivateDisableSwitchAccessDialogFunction() = default; |
| |
| AutotestPrivateDisableSwitchAccessDialogFunction:: |
| ~AutotestPrivateDisableSwitchAccessDialogFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| AutotestPrivateDisableSwitchAccessDialogFunction::Run() { |
| auto* accessibility_controller = ash::AccessibilityController::Get(); |
| accessibility_controller |
| ->DisableSwitchAccessDisableConfirmationDialogTesting(); |
| return RespondNow(NoArguments()); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateDisableAutomationFunction |
| ////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateDisableAutomationFunction:: |
| AutotestPrivateDisableAutomationFunction() = default; |
| |
| AutotestPrivateDisableAutomationFunction:: |
| ~AutotestPrivateDisableAutomationFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| AutotestPrivateDisableAutomationFunction::Run() { |
| AutomationManagerAura::GetInstance()->Disable(); |
| return RespondNow(NoArguments()); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateStartThroughputTrackerDataCollectionFunction |
| ////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateStartThroughputTrackerDataCollectionFunction:: |
| AutotestPrivateStartThroughputTrackerDataCollectionFunction() = default; |
| |
| AutotestPrivateStartThroughputTrackerDataCollectionFunction:: |
| ~AutotestPrivateStartThroughputTrackerDataCollectionFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| AutotestPrivateStartThroughputTrackerDataCollectionFunction::Run() { |
| ash::metrics_util::StartDataCollection(); |
| return RespondNow(NoArguments()); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateStopThroughputTrackerDataCollectionFunction |
| ////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateStopThroughputTrackerDataCollectionFunction:: |
| AutotestPrivateStopThroughputTrackerDataCollectionFunction() = default; |
| |
| AutotestPrivateStopThroughputTrackerDataCollectionFunction:: |
| ~AutotestPrivateStopThroughputTrackerDataCollectionFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| AutotestPrivateStopThroughputTrackerDataCollectionFunction::Run() { |
| auto collected_data = ash::metrics_util::StopDataCollection(); |
| std::vector<api::autotest_private::ThroughputTrackerAnimationData> |
| result_data; |
| for (const auto& data : collected_data) { |
| api::autotest_private::ThroughputTrackerAnimationData animation_data; |
| animation_data.frames_expected = data.frames_expected; |
| animation_data.frames_produced = data.frames_produced; |
| animation_data.jank_count = data.jank_count; |
| result_data.emplace_back(std::move(animation_data)); |
| } |
| |
| return RespondNow( |
| ArgumentList(api::autotest_private::StopThroughputTrackerDataCollection:: |
| Results::Create(result_data))); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateAPI |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| static base::LazyInstance<BrowserContextKeyedAPIFactory<AutotestPrivateAPI>>:: |
| DestructorAtExit g_autotest_private_api_factory = LAZY_INSTANCE_INITIALIZER; |
| |
| // static |
| BrowserContextKeyedAPIFactory<AutotestPrivateAPI>* |
| AutotestPrivateAPI::GetFactoryInstance() { |
| return g_autotest_private_api_factory.Pointer(); |
| } |
| |
| template <> |
| KeyedService* |
| BrowserContextKeyedAPIFactory<AutotestPrivateAPI>::BuildServiceInstanceFor( |
| content::BrowserContext* context) const { |
| return new AutotestPrivateAPI(context); |
| } |
| |
| AutotestPrivateAPI::AutotestPrivateAPI(content::BrowserContext* context) |
| : browser_context_(context), test_mode_(false) { |
| clipboard_observation_.Observe(ui::ClipboardMonitor::GetInstance()); |
| } |
| |
| AutotestPrivateAPI::~AutotestPrivateAPI() = default; |
| |
| void AutotestPrivateAPI::OnClipboardDataChanged() { |
| EventRouter* event_router = EventRouter::Get(browser_context_); |
| if (!event_router) |
| return; |
| |
| std::unique_ptr<Event> event( |
| new Event(events::AUTOTESTPRIVATE_ON_CLIPBOARD_DATA_CHANGED, |
| api::autotest_private::OnClipboardDataChanged::kEventName, |
| std::vector<base::Value>())); |
| event_router->BroadcastEvent(std::move(event)); |
| } |
| |
| } // namespace extensions |