| // Copyright 2012 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/ash/extensions/autotest_private/autotest_private_api.h" |
| |
| #include <deque> |
| #include <map> |
| #include <memory> |
| #include <set> |
| #include <sstream> |
| #include <utility> |
| |
| #include "ash/app_list/app_list_public_test_util.h" |
| #include "ash/components/arc/arc_prefs.h" |
| #include "ash/components/arc/metrics/arc_metrics_constants.h" |
| #include "ash/components/arc/mojom/system_ui.mojom-shared.h" |
| #include "ash/components/arc/session/arc_bridge_service.h" |
| #include "ash/components/arc/session/arc_service_manager.h" |
| #include "ash/components/arc/system_ui/arc_system_ui_bridge.h" |
| #include "ash/constants/app_types.h" |
| #include "ash/constants/ash_pref_names.h" |
| #include "ash/constants/ash_switches.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/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/holding_space/holding_space_model.h" |
| #include "ash/public/cpp/holding_space/holding_space_prefs.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/style/dark_light_mode_controller.h" |
| #include "ash/public/cpp/tablet_mode.h" |
| #include "ash/public/cpp/window_properties.h" |
| #include "ash/root_window_controller.h" |
| #include "ash/rotator/screen_rotation_animator.h" |
| #include "ash/shell.h" |
| #include "ash/wallpaper/wallpaper_widget_controller.h" |
| #include "ash/wm/overview/overview_controller.h" |
| #include "ash/wm/wm_event.h" |
| #include "base/base64.h" |
| #include "base/command_line.h" |
| #include "base/compiler_specific.h" |
| #include "base/feature_list.h" |
| #include "base/functional/bind.h" |
| #include "base/i18n/base_i18n_switches.h" |
| #include "base/json/json_reader.h" |
| #include "base/json/values_util.h" |
| #include "base/lazy_instance.h" |
| #include "base/memory/weak_ptr.h" |
| #include "base/no_destructor.h" |
| #include "base/numerics/safe_conversions.h" |
| #include "base/ranges/algorithm.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/system/sys_info.h" |
| #include "base/task/sequenced_task_runner.h" |
| #include "base/task/single_thread_task_runner.h" |
| #include "base/time/time.h" |
| #include "base/timer/timer.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/app_list/arc/arc_app_list_prefs.h" |
| #include "chrome/browser/ash/app_list/arc/arc_app_utils.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/crosapi/automation_ash.h" |
| #include "chrome/browser/ash/crosapi/browser_util.h" |
| #include "chrome/browser/ash/crosapi/crosapi_ash.h" |
| #include "chrome/browser/ash/crosapi/crosapi_manager.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/file_manager/open_util.h" |
| #include "chrome/browser/ash/file_manager/path_util.h" |
| #include "chrome/browser/ash/fusebox/fusebox_server.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/login/ui/login_display_host.h" |
| #include "chrome/browser/ash/login/wizard_context.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/policy/core/browser_policy_connector_ash.h" |
| #include "chrome/browser/ash/policy/core/user_cloud_policy_manager_ash.h" |
| #include "chrome/browser/ash/power/ml/smart_dim/ml_agent.h" |
| #include "chrome/browser/ash/printing/cups_printers_manager.h" |
| #include "chrome/browser/ash/printing/cups_printers_manager_factory.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/ash/system_web_apps/system_web_app_manager.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/component_updater/smart_dim_component_installer.h" |
| #include "chrome/browser/extensions/component_loader.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/signin/identity_manager_factory.h" |
| #include "chrome/browser/ui/ash/default_pinned_apps.h" |
| #include "chrome/browser/ui/ash/holding_space/holding_space_keyed_service.h" |
| #include "chrome/browser/ui/ash/holding_space/holding_space_keyed_service_factory.h" |
| #include "chrome/browser/ui/ash/shelf/chrome_shelf_controller.h" |
| #include "chrome/browser/ui/ash/shelf/chrome_shelf_controller_util.h" |
| #include "chrome/browser/ui/ash/shelf/shelf_spinner_controller.h" |
| #include "chrome/browser/ui/ash/system_web_apps/system_web_app_ui_utils.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/webui/ash/crostini_installer/crostini_installer_dialog.h" |
| #include "chrome/browser/ui/webui/ash/crostini_installer/crostini_installer_ui.h" |
| #include "chrome/browser/web_applications/app_registrar_observer.h" |
| #include "chrome/browser/web_applications/web_app_provider.h" |
| #include "chrome/browser/web_applications/web_app_registrar.h" |
| #include "chrome/common/extensions/api/autotest_private.h" |
| #include "chrome/common/pref_names.h" |
| #include "chromeos/ash/components/dbus/dbus_thread_manager.h" |
| #include "chromeos/ash/components/dbus/session_manager/session_manager_client.h" |
| #include "chromeos/ash/components/login/auth/public/user_context.h" |
| #include "chromeos/ash/components/metrics/login_event_recorder.h" |
| #include "chromeos/ash/components/settings/cros_settings_names.h" |
| #include "chromeos/ash/services/assistant/assistant_manager_service_impl.h" |
| #include "chromeos/ash/services/assistant/public/cpp/assistant_prefs.h" |
| #include "chromeos/ash/services/assistant/public/cpp/assistant_service.h" |
| #include "chromeos/components/quick_answers/public/cpp/quick_answers_prefs.h" |
| #include "chromeos/printing/printer_configuration.h" |
| #include "chromeos/services/machine_learning/public/cpp/service_connection.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 "chromeos/ui/wm/desks/desks_helper.h" |
| #include "components/app_restore/full_restore_utils.h" |
| #include "components/app_restore/window_properties.h" |
| #include "components/policy/core/browser/policy_conversions.h" |
| #include "components/policy/core/common/cloud/cloud_policy_manager.h" |
| #include "components/policy/core/common/policy_service.h" |
| #include "components/policy/core/common/remote_commands/remote_commands_service.h" |
| #include "components/prefs/pref_service.h" |
| #include "components/services/app_service/public/cpp/app_types.h" |
| #include "components/services/app_service/public/cpp/types_util.h" |
| #include "components/services/app_service/public/mojom/types.mojom.h" |
| #include "components/session_manager/core/session_manager.h" |
| #include "components/session_manager/session_manager_types.h" |
| #include "components/signin/public/identity_manager/access_token_info.h" |
| #include "components/signin/public/identity_manager/identity_manager.h" |
| #include "components/update_client/update_client_errors.h" |
| #include "components/user_manager/user.h" |
| #include "components/user_manager/user_manager.h" |
| #include "components/variations/pref_names.h" |
| #include "components/viz/host/host_frame_sink_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/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 "services/viz/public/mojom/compositing/compositor_frame_sink.mojom-shared.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/ash/ime_bridge.h" |
| #include "ui/base/ime/ash/text_input_method.h" |
| #include "ui/base/ui_base_features.h" |
| #include "ui/compositor/compositor.h" |
| #include "ui/compositor/layer.h" |
| #include "ui/compositor/layer_animator.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_properties.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"; |
| |
| NOINLINE int AccessArray(const int arr[], const int* index) { |
| return arr[*index]; |
| } |
| |
| base::Value::List 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::Value::List permissions; |
| for (const auto& perm : *pattern_set) |
| permissions.Append(perm.GetAsString()); |
| |
| return permissions; |
| } |
| |
| base::Value::List GetAPIPermissions(const Extension* ext) { |
| base::Value::List permissions; |
| std::set<std::string> perm_list = |
| ext->permissions_data()->active_permissions().GetAPIsAsStrings(); |
| for (const auto& perm : perm_list) { |
| permissions.Append(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: |
| case message_center::DEPRECATED_NOTIFICATION_TYPE_BASE_FORMAT: |
| return "simple"; |
| 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"; |
| } |
| |
| base::Value::Dict MakeDictionaryFromNotification( |
| const message_center::Notification& notification) { |
| base::Value::Dict result; |
| result.Set("id", notification.id()); |
| result.Set("type", ConvertToString(notification.type())); |
| result.Set("title", notification.title()); |
| result.Set("message", notification.message()); |
| result.Set("priority", notification.priority()); |
| result.Set("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::AppType type) { |
| switch (type) { |
| case apps::AppType::kArc: |
| return api::autotest_private::AppType::APP_TYPE_ARC; |
| case apps::AppType::kBuiltIn: |
| return api::autotest_private::AppType::APP_TYPE_BUILTIN; |
| case apps::AppType::kCrostini: |
| return api::autotest_private::AppType::APP_TYPE_CROSTINI; |
| case apps::AppType::kChromeApp: |
| case apps::AppType::kExtension: |
| return api::autotest_private::AppType::APP_TYPE_EXTENSION; |
| case apps::AppType::kPluginVm: |
| return api::autotest_private::AppType::APP_TYPE_PLUGINVM; |
| case apps::AppType::kWeb: |
| case apps::AppType::kSystemWeb: |
| return api::autotest_private::AppType::APP_TYPE_WEB; |
| case apps::AppType::kUnknown: |
| return api::autotest_private::AppType::APP_TYPE_NONE; |
| case apps::AppType::kMacOs: |
| return api::autotest_private::AppType::APP_TYPE_MACOS; |
| case apps::AppType::kStandaloneBrowser: |
| return api::autotest_private::AppType::APP_TYPE_STANDALONEBROWSER; |
| case apps::AppType::kRemote: |
| return api::autotest_private::AppType::APP_TYPE_REMOTE; |
| case apps::AppType::kBorealis: |
| return api::autotest_private::AppType::APP_TYPE_BOREALIS; |
| case apps::AppType::kBruschetta: |
| return api::autotest_private::AppType::APP_TYPE_BRUSCHETTA; |
| case apps::AppType::kStandaloneBrowserExtension: |
| return api::autotest_private::AppType::APP_TYPE_NONE; |
| case apps::AppType::kStandaloneBrowserChromeApp: |
| return api::autotest_private::AppType::APP_TYPE_EXTENSION; |
| } |
| NOTREACHED(); |
| return api::autotest_private::AppType::APP_TYPE_NONE; |
| } |
| |
| api::autotest_private::AppInstallSource GetAppInstallSource( |
| apps::InstallReason install_reason) { |
| switch (install_reason) { |
| case apps::InstallReason::kUnknown: |
| return api::autotest_private::AppInstallSource:: |
| APP_INSTALL_SOURCE_UNKNOWN; |
| case apps::InstallReason::kSystem: |
| return api::autotest_private::AppInstallSource::APP_INSTALL_SOURCE_SYSTEM; |
| case apps::InstallReason::kPolicy: |
| return api::autotest_private::AppInstallSource::APP_INSTALL_SOURCE_POLICY; |
| case apps::InstallReason::kOem: |
| return api::autotest_private::AppInstallSource::APP_INSTALL_SOURCE_OEM; |
| case apps::InstallReason::kDefault: |
| return api::autotest_private::AppInstallSource:: |
| APP_INSTALL_SOURCE_DEFAULT; |
| case apps::InstallReason::kSync: |
| return api::autotest_private::AppInstallSource::APP_INSTALL_SOURCE_SYNC; |
| case apps::InstallReason::kUser: |
| return api::autotest_private::AppInstallSource::APP_INSTALL_SOURCE_USER; |
| case apps::InstallReason::kSubApp: |
| return api::autotest_private::AppInstallSource::APP_INSTALL_SOURCE_SUBAPP; |
| case apps::InstallReason::kKiosk: |
| return api::autotest_private::AppInstallSource::APP_INSTALL_SOURCE_KIOSK; |
| case apps::InstallReason::kCommandLine: |
| return api::autotest_private::AppInstallSource:: |
| APP_INSTALL_SOURCE_COMMANDLINE; |
| } |
| 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::Readiness readiness) { |
| switch (readiness) { |
| case apps::Readiness::kReady: |
| return api::autotest_private::AppReadiness::APP_READINESS_READY; |
| case apps::Readiness::kDisabledByBlocklist: |
| return api::autotest_private::AppReadiness:: |
| APP_READINESS_DISABLEDBYBLACKLIST; |
| case apps::Readiness::kDisabledByPolicy: |
| return api::autotest_private::AppReadiness:: |
| APP_READINESS_DISABLEDBYPOLICY; |
| case apps::Readiness::kDisabledByUser: |
| return api::autotest_private::AppReadiness::APP_READINESS_DISABLEDBYUSER; |
| case apps::Readiness::kTerminated: |
| return api::autotest_private::AppReadiness::APP_READINESS_TERMINATED; |
| case apps::Readiness::kUninstalledByUser: |
| return api::autotest_private::AppReadiness:: |
| APP_READINESS_UNINSTALLEDBYUSER; |
| case apps::Readiness::kRemoved: |
| return api::autotest_private::AppReadiness::APP_READINESS_REMOVED; |
| case apps::Readiness::kUninstalledByMigration: |
| return api::autotest_private::AppReadiness:: |
| APP_READINESS_UNINSTALLEDBYMIGRATION; |
| case apps::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(); |
| } |
| |
| // Helper function to set allowed user pref based on |pref_name| with any |
| // specific pref validations. Returns error messages if any. |
| std::string SetAllowedPref(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 == variations::prefs::kVariationsCompressedSeed || |
| pref_name == variations::prefs::kVariationsSeedSignature) { |
| DCHECK(value.is_string()); |
| g_browser_process->local_state()->Set(pref_name, value); |
| return std::string(); |
| } |
| |
| if (pref_name == ash::assistant::prefs::kAssistantEnabled) { |
| if (!value.is_bool()) |
| return "Invalid value type."; |
| // Validate the Assistant service allowed state. |
| ash::assistant::AssistantAllowedState allowed_state = |
| assistant::IsAssistantAllowedForProfile(profile); |
| if (allowed_state != ash::assistant::AssistantAllowedState::ALLOWED) { |
| return base::StringPrintf("Assistant not allowed - state: %d", |
| allowed_state); |
| } |
| } else if (pref_name == ash::assistant::prefs::kAssistantConsentStatus) { |
| if (!value.is_int()) |
| return "Invalid value type."; |
| if (!profile->GetPrefs()->GetBoolean( |
| ash::assistant::prefs::kAssistantEnabled)) { |
| return "Unable to set the pref because Assistant has not been enabled."; |
| } |
| } else if (pref_name == ash::assistant::prefs::kAssistantContextEnabled || |
| pref_name == ash::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( |
| ash::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::kAccessibilitySpokenFeedbackEnabled) { |
| DCHECK(value.is_bool()); |
| } else if (pref_name == ash::prefs::kAccessibilityVirtualKeyboardEnabled) { |
| DCHECK(value.is_bool()); |
| } else if (pref_name == ash::prefs::kEnableAutoScreenLock) { |
| 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 if (pref_name == plugin_vm::prefs::kPluginVmDataCollectionAllowed) { |
| DCHECK(value.is_bool()); |
| } else if (pref_name == prefs::kPrintingAPIExtensionsAllowlist) { |
| DCHECK(value.is_list()); |
| } else if (pref_name == quick_answers::prefs::kQuickAnswersEnabled) { |
| DCHECK(value.is_bool()); |
| } else if (pref_name == |
| quick_answers::prefs::kQuickAnswersDefinitionEnabled) { |
| DCHECK(value.is_bool()); |
| } else if (pref_name == |
| quick_answers::prefs::kQuickAnswersTranslationEnabled) { |
| DCHECK(value.is_bool()); |
| } else if (pref_name == |
| quick_answers::prefs::kQuickAnswersUnitConversionEnabled) { |
| DCHECK(value.is_bool()); |
| } else if (pref_name == quick_answers::prefs::kQuickAnswersConsentStatus) { |
| DCHECK(value.is_int()); |
| } else if (pref_name == arc::prefs::kArcShowResizeLockSplashScreenLimits) { |
| DCHECK(value.is_int()); |
| } else { |
| return "The pref " + pref_name + " is not allowed."; |
| } |
| |
| // 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; |
| case api::autotest_private::WMEventType::WM_EVENT_TYPE_WMEVENTFLOAT: |
| return chromeos::WindowStateType::kFloated; |
| 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; |
| case api::autotest_private::WMEventType::WM_EVENT_TYPE_WMEVENTFLOAT: |
| return ash::WMEventType::WM_EVENT_FLOAT; |
| 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; |
| case chromeos::WindowStateType::kFloated: |
| return api::autotest_private::WindowStateType::WINDOW_STATE_TYPE_FLOATED; |
| 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; |
| } |
| |
| arc::mojom::ThemeStyleType ToThemeStyleType( |
| const api::autotest_private::ThemeStyle& theme) { |
| switch (theme) { |
| case api::autotest_private::ThemeStyle::THEME_STYLE_TONALSPOT: |
| return arc::mojom::ThemeStyleType::TONAL_SPOT; |
| case api::autotest_private::ThemeStyle::THEME_STYLE_VIBRANT: |
| return arc::mojom::ThemeStyleType::VIBRANT; |
| case api::autotest_private::ThemeStyle::THEME_STYLE_EXPRESSIVE: |
| return arc::mojom::ThemeStyleType::EXPRESSIVE; |
| case api::autotest_private::ThemeStyle::THEME_STYLE_SPRITZ: |
| return arc::mojom::ThemeStyleType::SPRITZ; |
| case api::autotest_private::ThemeStyle::THEME_STYLE_RAINBOW: |
| return arc::mojom::ThemeStyleType::RAINBOW; |
| case api::autotest_private::ThemeStyle::THEME_STYLE_FRUITSALAD: |
| return arc::mojom::ThemeStyleType::FRUIT_SALAD; |
| default: |
| return arc::mojom::ThemeStyleType::TONAL_SPOT; |
| } |
| } |
| |
| aura::Window* FindAppWindowById(const int64_t id) { |
| auto list = ash::GetAppWindowList(); |
| auto iter = base::ranges::find(list, id, &aura::Window::GetId); |
| 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(); |
| const web_app::AppBrowserController* (Browser::*app_controller)() const = |
| &Browser::app_controller; |
| auto iter = base::ranges::find(*list, nullptr, app_controller); |
| 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_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) { |
| *location = root_window->GetHost()->GetRootTransform().MapPoint(*location); |
| } |
| |
| 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; |
| case api::autotest_private::MOUSE_BUTTON_BACK: |
| return ui::EF_BACK_MOUSE_BUTTON; |
| case api::autotest_private::MOUSE_BUTTON_FORWARD: |
| return ui::EF_FORWARD_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 absl::optional<std::string>& arg, |
| int64_t* display_id) { |
| if (arg && !arg->empty()) { |
| return base::StringToInt64(*arg, display_id); |
| } |
| |
| *display_id = display::Screen::GetScreen()->GetPrimaryDisplay().id(); |
| return true; |
| } |
| |
| class DisplaySmoothnessTracker { |
| public: |
| using ReportCallback = base::OnceCallback<void( |
| const cc::FrameSequenceMetrics::CustomReportData& frame_data, |
| std::vector<int>&& throughput)>; |
| |
| DisplaySmoothnessTracker() = default; |
| DisplaySmoothnessTracker(const DisplaySmoothnessTracker&) = delete; |
| DisplaySmoothnessTracker& operator=(const DisplaySmoothnessTracker&) = delete; |
| ~DisplaySmoothnessTracker() = default; |
| |
| // Return true if tracking is started successfully. |
| bool Start(int64_t display_id, |
| base::TimeDelta throughput_interval, |
| ui::ThroughputTrackerHost::ReportCallback callback) { |
| auto* root_window = ash::Shell::GetRootWindowForDisplayId(display_id); |
| if (!root_window) |
| return false; |
| |
| DCHECK(root_window_tracker_.windows().empty()); |
| root_window_tracker_.Add(root_window); |
| |
| tracker_ = |
| root_window->layer()->GetCompositor()->RequestNewThroughputTracker(); |
| tracker_->Start(std::move(callback)); |
| |
| throughtput_timer_.Start(FROM_HERE, throughput_interval, this, |
| &DisplaySmoothnessTracker::OnThroughputTimerFired); |
| |
| return true; |
| } |
| |
| void Stop(ReportCallback callback) { |
| stopping_ = true; |
| throughtput_timer_.Stop(); |
| callback_ = std::move(callback); |
| tracker_->Stop(); |
| } |
| |
| ReportCallback TakeCallback() { return std::move(callback_); } |
| std::vector<int> TakeThroughput() { return std::move(throughput_); } |
| |
| bool stopping() const { return stopping_; } |
| bool has_error() const { return has_error_; } |
| |
| private: |
| void OnThroughputTimerFired() { |
| auto windows = root_window_tracker_.windows(); |
| if (windows.empty()) { |
| // RootWindow is gone. This could happen when display is reconfigured |
| // during the test run. Treat it as error since no meaningful smoothness |
| // data would be captured in such case. |
| LOG(ERROR) << "Unable to collect throughput because underlying " |
| "RootWindow is gone."; |
| has_error_ = true; |
| throughtput_timer_.Stop(); |
| return; |
| } |
| |
| DCHECK_EQ(windows.size(), 1u); |
| auto* root_window = windows[0]; |
| throughput_.push_back( |
| 100 - root_window->GetHost()->compositor()->GetPercentDroppedFrames()); |
| } |
| |
| aura::WindowTracker root_window_tracker_; |
| absl::optional<ui::ThroughputTracker> tracker_; |
| ReportCallback callback_; |
| bool stopping_ = false; |
| bool has_error_ = false; |
| |
| base::RepeatingTimer throughtput_timer_; |
| std::vector<int> throughput_; |
| }; |
| |
| using DisplaySmoothnessTrackers = |
| std::map<int64_t, std::unique_ptr<DisplaySmoothnessTracker>>; |
| DisplaySmoothnessTrackers* GetDisplaySmoothnessTrackers() { |
| static base::NoDestructor<DisplaySmoothnessTrackers> 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& frame_data) { |
| auto* trackers = GetDisplaySmoothnessTrackers(); |
| auto it = trackers->find(display_id); |
| DCHECK(it != trackers->end()); |
| |
| auto throughput = it->second->TakeThroughput(); |
| |
| // 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 = it->second->TakeCallback(); |
| DCHECK(callback); |
| trackers->erase(it); |
| std::move(callback).Run(frame_data, std::move(throughput)); |
| } |
| |
| std::string ResolutionToString( |
| ash::assistant::AssistantInteractionResolution resolution) { |
| using ash::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); |
| } |
| |
| std::string CompositorFrameSinkTypeToString( |
| viz::mojom::CompositorFrameSinkType type) { |
| switch (type) { |
| case viz::mojom::CompositorFrameSinkType::kUnspecified: |
| return "unspecified"; |
| case viz::mojom::CompositorFrameSinkType::kVideo: |
| return "video"; |
| case viz::mojom::CompositorFrameSinkType::kMediaStream: |
| return "media-stream"; |
| case viz::mojom::CompositorFrameSinkType::kLayerTree: |
| return "layer-tree"; |
| } |
| } |
| |
| // Update when `startThroughputTrackerDataCollection` is called. |
| base::TimeTicks g_last_start_throughput_data_collection_tick; |
| |
| } // 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(const WindowStateChangeObserver&) = delete; |
| WindowStateChangeObserver& operator=(const WindowStateChangeObserver&) = |
| delete; |
| |
| ~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_; |
| }; |
| |
| 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::Seconds(1) / |
| std::max(host->compositor()->refresh_rate(), 60.0f)), |
| closure_(std::move(closure)), |
| weak_ptr_factory_(this) { |
| // VM may report slightly lower than 60hz refresh rate. |
| LOG_IF(ERROR, host->compositor()->refresh_rate() < 59.98f) |
| << "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); |
| } |
| if (task->flags & ui::EF_BACK_MOUSE_BUTTON) { |
| input_injector_->InjectMouseButton(ui::EF_BACK_MOUSE_BUTTON, pressed); |
| } |
| if (task->flags & ui::EF_FORWARD_MOUSE_BUTTON) { |
| input_injector_->InjectMouseButton(ui::EF_FORWARD_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::SequencedTaskRunner::GetCurrentDefault()->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(); |
| const auto& runner = base::SequencedTaskRunner::GetCurrentDefault(); |
| 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"; |
| base::Value::Dict result; |
| 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 = |
| !!ash::ScreenLocker::default_screen_locker() && |
| ash::ScreenLocker::default_screen_locker()->locked(); |
| |
| if (user_manager) { |
| result.Set("isLoggedIn", user_manager->IsUserLoggedIn()); |
| result.Set("isOwner", user_manager->IsCurrentUserOwner()); |
| result.Set("isScreenLocked", is_screen_locked); |
| result.Set("isLockscreenWallpaperAnimating", |
| is_screen_locked && ash::Shell::Get() |
| ->GetPrimaryRootWindowController() |
| ->wallpaper_widget_controller() |
| ->IsAnimating()); |
| result.Set("isReadyForPassword", |
| ash::LoginScreen::Get()->IsReadyForPassword()); |
| if (user_manager->IsUserLoggedIn()) { |
| result.Set("isRegularUser", |
| user_manager->IsLoggedInAsUserWithGaiaAccount()); |
| result.Set("isGuest", user_manager->IsLoggedInAsGuest()); |
| result.Set("isKiosk", user_manager->IsLoggedInAsKioskApp()); |
| |
| const user_manager::User* user = user_manager->GetActiveUser(); |
| result.Set("email", user->GetAccountId().GetUserEmail()); |
| result.Set("displayEmail", user->display_email()); |
| result.Set("displayName", user->display_name()); |
| |
| 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.Set("userImage", user_image); |
| |
| if (user->HasGaiaAccount()) { |
| result.Set("hasValidOauth2Token", |
| user->oauth_token_status() == |
| user_manager::User::OAUTH2_TOKEN_STATUS_VALID); |
| } |
| } |
| } |
| return RespondNow(WithArguments(std::move(result))); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateLockScreenFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateLockScreenFunction::~AutotestPrivateLockScreenFunction() = |
| default; |
| |
| ExtensionFunction::ResponseAction AutotestPrivateLockScreenFunction::Run() { |
| DVLOG(1) << "AutotestPrivateLockScreenFunction"; |
| |
| ash::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::Dict all_policies_dict = |
| policy::DictionaryPolicyConversions(std::move(client)) |
| .EnableDeviceLocalAccountPolicies(true) |
| .EnableDeviceInfo(true) |
| .ToValueDict(); |
| |
| return RespondNow(WithArguments(std::move(all_policies_dict))); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // 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()); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateRefreshRemoteCommandsFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateRefreshRemoteCommandsFunction:: |
| ~AutotestPrivateRefreshRemoteCommandsFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| AutotestPrivateRefreshRemoteCommandsFunction::Run() { |
| DVLOG(1) << "AutotestPrivateRefreshRemoteCommandsFunction"; |
| // Allow tests to manually fetch remote commands. Useful for testing or when |
| // the invalidation service is not working properly. |
| policy::CloudPolicyManager* const device_manager = |
| g_browser_process->platform_part() |
| ->browser_policy_connector_ash() |
| ->GetDeviceCloudPolicyManager(); |
| policy::CloudPolicyManager* const user_manager = |
| Profile::FromBrowserContext(browser_context()) |
| ->GetUserCloudPolicyManagerAsh(); |
| |
| // Fetch both device and user remote commands. |
| for (policy::CloudPolicyManager* manager : {device_manager, user_manager}) { |
| if (manager) { |
| policy::RemoteCommandsService* const remote_commands_service = |
| manager->core()->remote_commands_service(); |
| if (remote_commands_service) |
| remote_commands_service->FetchRemoteCommands(); |
| } |
| } |
| // TODO(b/260972611): Wait till remote commands are fetched. |
| return RespondNow(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::Value::List 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(); |
| base::Value::Dict extension_value; |
| extension_value.Set("id", id); |
| extension_value.Set("version", extension->VersionString()); |
| extension_value.Set("name", extension->name()); |
| extension_value.Set("publicKey", extension->public_key()); |
| extension_value.Set("description", extension->description()); |
| extension_value.Set("backgroundUrl", |
| BackgroundInfo::GetBackgroundURL(extension).spec()); |
| extension_value.Set("optionsUrl", |
| OptionsPageInfo::GetOptionsPage(extension).spec()); |
| |
| extension_value.Set("hostPermissions", |
| GetHostPermissions(extension, false)); |
| extension_value.Set("effectiveHostPermissions", |
| GetHostPermissions(extension, true)); |
| extension_value.Set("apiPermissions", GetAPIPermissions(extension)); |
| |
| ManifestLocation location = extension->location(); |
| extension_value.Set("isComponent", |
| location == ManifestLocation::kComponent); |
| extension_value.Set("isInternal", location == ManifestLocation::kInternal); |
| extension_value.Set("isUserInstalled", |
| location == ManifestLocation::kInternal || |
| Manifest::IsUnpackedLocation(location)); |
| extension_value.Set("isEnabled", service->IsExtensionEnabled(id)); |
| extension_value.Set("allowedInIncognito", |
| util::IsIncognitoEnabled(id, browser_context())); |
| const ExtensionAction* action = |
| extension_action_manager->GetExtensionAction(*extension); |
| extension_value.Set("hasPageAction", action && action->action_type() == |
| ActionInfo::TYPE_PAGE); |
| |
| extensions_values.Append(std::move(extension_value)); |
| } |
| |
| base::Value::Dict return_value; |
| return_value.Set("extensions", std::move(extensions_values)); |
| return RespondNow(WithArguments(std::move(return_value))); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateSimulateAsanMemoryBugFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateSimulateAsanMemoryBugFunction:: |
| ~AutotestPrivateSimulateAsanMemoryBugFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| AutotestPrivateSimulateAsanMemoryBugFunction::Run() { |
| DVLOG(1) << "AutotestPrivateSimulateAsanMemoryBugFunction"; |
| |
| if (!IsTestMode(browser_context())) { |
| int testarray[3] = {0, 0, 0}; |
| |
| // Cause Address Sanitizer to abort this process. |
| 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; |
| |
| ash::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; |
| |
| ash::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; |
| |
| ash::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; |
| |
| ash::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; |
| |
| ash::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; |
| |
| ash::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; |
| |
| ash::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; |
| |
| ash::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(); |
| base::Value::List values; |
| for (auto* notification : notification_set) |
| values.Append(MakeDictionaryFromNotification(*notification)); |
| return RespondNow(WithArguments(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(WithArguments(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(WithArguments(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 = arc::IsArcPlayStoreEnabledForProfile(profile); |
| play_store_state.managed = |
| arc::IsArcPlayStoreEnabledPreferenceManagedForProfile(profile); |
| } |
| return RespondNow(WithArguments(play_store_state.ToValue())); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateStartArcFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateStartArcFunction::~AutotestPrivateStartArcFunction() = default; |
| |
| ExtensionFunction::ResponseAction AutotestPrivateStartArcFunction::Run() { |
| DVLOG(1) << "AutotestPrivateStartArcFunction"; |
| |
| arc::ArcSessionManager* arc_session_manager = arc::ArcSessionManager::Get(); |
| if (!arc_session_manager) |
| return RespondNow(Error("Could not find ARC session manager")); |
| |
| Profile* profile = Profile::FromBrowserContext(browser_context()); |
| if (!arc::IsArcAllowedForProfile(profile)) |
| return RespondNow(Error("ARC cannot be started for the current user")); |
| |
| if (arc_session_manager->enable_requested()) |
| return RespondNow(Error("ARC is already started")); |
| |
| arc_session_manager->RequestEnable(); |
| |
| return RespondNow(NoArguments()); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateStopArcFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateStopArcFunction::~AutotestPrivateStopArcFunction() = default; |
| |
| ExtensionFunction::ResponseAction AutotestPrivateStopArcFunction::Run() { |
| DVLOG(1) << "AutotestPrivateStopArcFunction"; |
| |
| arc::ArcSessionManager* arc_session_manager = arc::ArcSessionManager::Get(); |
| if (!arc_session_manager) |
| return RespondNow(Error("Could not find ARC session manager")); |
| |
| if (!arc_session_manager->enable_requested()) |
| return RespondNow(Error("ARC is already stopped")); |
| |
| arc_session_manager->RequestDisable(); |
| |
| return RespondNow(NoArguments()); |
| } |
| /////////////////////////////////////////////////////////////////////////////// |
| // 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 |
| // SetAllowedPref. 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(WithArguments(window_attached)); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateIsAppShownFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateIsArcProvisionedFunction:: |
| ~AutotestPrivateIsArcProvisionedFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| AutotestPrivateIsArcProvisionedFunction::Run() { |
| DVLOG(1) << "AutotestPrivateIsArcProvisionedFunction"; |
| return RespondNow(WithArguments( |
| arc::IsArcProvisioned(Profile::FromBrowserContext(browser_context())))); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateGetLacrosInfoFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateGetLacrosInfoFunction::~AutotestPrivateGetLacrosInfoFunction() = |
| default; |
| |
| // static |
| api::autotest_private::LacrosState |
| AutotestPrivateGetLacrosInfoFunction::ToLacrosState( |
| crosapi::BrowserManager::State state) { |
| switch (state) { |
| case crosapi::BrowserManager::State::NOT_INITIALIZED: |
| return api::autotest_private::LACROS_STATE_NOTINITIALIZED; |
| case crosapi::BrowserManager::State::MOUNTING: |
| return api::autotest_private::LACROS_STATE_MOUNTING; |
| case crosapi::BrowserManager::State::UNAVAILABLE: |
| return api::autotest_private::LACROS_STATE_UNAVAILABLE; |
| case crosapi::BrowserManager::State::STOPPED: |
| return api::autotest_private::LACROS_STATE_STOPPED; |
| case crosapi::BrowserManager::State::CREATING_LOG_FILE: |
| return api::autotest_private::LACROS_STATE_CREATINGLOGFILE; |
| case crosapi::BrowserManager::State::STARTING: |
| return api::autotest_private::LACROS_STATE_STARTING; |
| case crosapi::BrowserManager::State::RUNNING: |
| return api::autotest_private::LACROS_STATE_RUNNING; |
| case crosapi::BrowserManager::State::TERMINATING: |
| return api::autotest_private::LACROS_STATE_TERMINATING; |
| } |
| } |
| |
| // static |
| api::autotest_private::LacrosMode |
| AutotestPrivateGetLacrosInfoFunction::ToLacrosMode( |
| crosapi::browser_util::LacrosMode lacrosMode) { |
| switch (lacrosMode) { |
| case crosapi::browser_util::LacrosMode::kDisabled: |
| return api::autotest_private::LacrosMode::LACROS_MODE_DISABLED; |
| case crosapi::browser_util::LacrosMode::kSideBySide: |
| return api::autotest_private::LacrosMode::LACROS_MODE_SIDEBYSIDE; |
| case crosapi::browser_util::LacrosMode::kPrimary: |
| return api::autotest_private::LacrosMode::LACROS_MODE_PRIMARY; |
| case crosapi::browser_util::LacrosMode::kOnly: |
| return api::autotest_private::LacrosMode::LACROS_MODE_ONLY; |
| } |
| } |
| |
| ExtensionFunction::ResponseAction AutotestPrivateGetLacrosInfoFunction::Run() { |
| DVLOG(1) << "AutotestPrivateGetLacrosInfoFunction"; |
| auto* browser_manager = crosapi::BrowserManager::Get(); |
| base::Value::Dict result; |
| result.Set("state", api::autotest_private::ToString( |
| ToLacrosState(browser_manager->state_))); |
| result.Set("isKeepAlive", browser_manager->IsKeepAliveEnabled()); |
| result.Set("lacrosPath", browser_manager->lacros_path().MaybeAsASCII()); |
| result.Set("mode", api::autotest_private::ToString( |
| ToLacrosMode(crosapi::browser_util::GetLacrosMode()))); |
| return RespondNow(WithArguments(std::move(result))); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateGetArcAppFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| 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")); |
| |
| base::Value::Dict 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.Set("name", std::move(app_info->name)); |
| app_value.Set("packageName", std::move(app_info->package_name)); |
| app_value.Set("activity", std::move(app_info->activity)); |
| app_value.Set("intentUri", std::move(app_info->intent_uri)); |
| app_value.Set("iconResourceId", std::move(app_info->icon_resource_id)); |
| app_value.Set("lastLaunchTime", app_info->last_launch_time.ToJsTime()); |
| app_value.Set("installTime", app_info->install_time.ToJsTime()); |
| app_value.Set("sticky", app_info->sticky); |
| app_value.Set("notificationsEnabled", app_info->notifications_enabled); |
| app_value.Set("ready", app_info->ready); |
| app_value.Set("suspended", app_info->suspended); |
| app_value.Set("showInLauncher", app_info->show_in_launcher); |
| app_value.Set("shortcut", app_info->shortcut); |
| app_value.Set("launchable", app_info->launchable); |
| } |
| |
| return RespondNow(WithArguments(std::move(app_value))); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateGetArcAppKillsFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateGetArcAppKillsFunction:: |
| ~AutotestPrivateGetArcAppKillsFunction() = default; |
| |
| ExtensionFunction::ResponseAction AutotestPrivateGetArcAppKillsFunction::Run() { |
| DVLOG(1) << "AutotestPrivateGetArcAppKillsFunction"; |
| |
| arc::ArcServiceManager* arc_service_manager = arc::ArcServiceManager::Get(); |
| if (!arc_service_manager) |
| return RespondNow(Error("ARC service manager is not available")); |
| |
| arc::ArcBridgeService* arc_bridge_service = |
| arc_service_manager->arc_bridge_service(); |
| |
| if (!arc_bridge_service) |
| return RespondNow(Error("ARC bridge service is not available")); |
| |
| arc::mojom::ProcessInstance* process_instance = ARC_GET_INSTANCE_FOR_METHOD( |
| arc_bridge_service->process(), RequestLowMemoryKillCounts); |
| |
| if (!process_instance) |
| return RespondNow(Error("ARC process service is not available")); |
| |
| process_instance->RequestLowMemoryKillCounts(base::BindOnce( |
| &AutotestPrivateGetArcAppKillsFunction::OnKillCounts, this)); |
| |
| return RespondLater(); |
| } |
| |
| void AutotestPrivateGetArcAppKillsFunction::OnKillCounts( |
| arc::mojom::LowMemoryKillCountsPtr counts) { |
| api::autotest_private::ArcAppKillsDict result; |
| result.oom = counts->guest_oom; |
| result.lmkd_foreground = counts->lmkd_foreground; |
| result.lmkd_perceptible = counts->lmkd_perceptible; |
| result.lmkd_cached = counts->lmkd_cached; |
| result.pressure_foreground = counts->pressure_foreground; |
| result.pressure_perceptible = counts->pressure_perceptible; |
| result.pressure_cached = counts->pressure_cached; |
| Respond(WithArguments(result.ToValue())); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // 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")); |
| |
| base::Value::Dict 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.Set("packageName", std::move(package_info->package_name)); |
| package_value.Set("packageVersion", package_info->package_version); |
| package_value.Set( |
| "lastBackupAndroidId", |
| base::NumberToString(package_info->last_backup_android_id)); |
| package_value.Set("lastBackupTime", |
| base::Time::FromDeltaSinceWindowsEpoch( |
| base::Microseconds(package_info->last_backup_time)) |
| .ToJsTime()); |
| package_value.Set("shouldSync", package_info->should_sync); |
| package_value.Set("vpnProvider", package_info->vpn_provider); |
| } |
| return RespondNow(WithArguments(std::move(package_value))); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateGetCryptohomeRecoveryDataFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateGetCryptohomeRecoveryDataFunction:: |
| ~AutotestPrivateGetCryptohomeRecoveryDataFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| AutotestPrivateGetCryptohomeRecoveryDataFunction::Run() { |
| // The API is available only on test images. |
| base::SysInfo::CrashIfChromeOSNonTestImage(); |
| |
| if (!base::CommandLine::ForCurrentProcess()->HasSwitch( |
| ash::switches::kForceCryptohomeRecoveryForTesting)) { |
| return RespondNow( |
| Error("force-cryptohome-recovery-for-testing switch is not set")); |
| } |
| |
| auto* host = ash::LoginDisplayHost::default_host(); |
| if (!host) |
| return RespondNow(Error("LoginDisplayHost is not available")); |
| auto* context = host->GetWizardContext(); |
| if (!context) |
| return RespondNow(Error("WizardContext is not available")); |
| |
| ash::UserContext* user_context = context->extra_factors_auth_session.get(); |
| if (!user_context) |
| return RespondNow(Error("UserContext is not available")); |
| |
| std::string reauth_proof_token = user_context->GetReauthProofToken(); |
| std::string refresh_token = user_context->GetRefreshToken(); |
| if (reauth_proof_token.empty() || refresh_token.empty()) { |
| return RespondNow(Error("Tokens are empty")); |
| } |
| |
| api::autotest_private::CryptohomeRecoveryDataDict result; |
| result.reauth_proof_token = reauth_proof_token; |
| result.refresh_token = refresh_token; |
| |
| return RespondNow(WithArguments(result.ToValue())); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateWaitForSystemWebAppsInstallFunction |
| ////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateWaitForSystemWebAppsInstallFunction:: |
| AutotestPrivateWaitForSystemWebAppsInstallFunction() = default; |
| |
| AutotestPrivateWaitForSystemWebAppsInstallFunction:: |
| ~AutotestPrivateWaitForSystemWebAppsInstallFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| AutotestPrivateWaitForSystemWebAppsInstallFunction::Run() { |
| Profile* profile = Profile::FromBrowserContext(browser_context()); |
| ash::SystemWebAppManager* swa_manager = |
| ash::SystemWebAppManager::Get(profile); |
| |
| if (!swa_manager) |
| return RespondNow(Error("System Web Apps are not available for profile.")); |
| |
| swa_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()); |
| ash::SystemWebAppManager* swa_manager = |
| ash::SystemWebAppManager::Get(profile); |
| |
| if (!swa_manager) |
| return RespondNow(Error("System Web Apps are not available for profile.")); |
| |
| swa_manager->on_apps_synchronized().Post( |
| FROM_HERE, |
| base::BindOnce(&AutotestPrivateGetRegisteredSystemWebAppsFunction:: |
| OnSystemWebAppsInstalled, |
| this)); |
| return RespondLater(); |
| } |
| |
| void AutotestPrivateGetRegisteredSystemWebAppsFunction:: |
| OnSystemWebAppsInstalled() { |
| Profile* profile = Profile::FromBrowserContext(browser_context()); |
| ash::SystemWebAppManager* swa_manager = |
| ash::SystemWebAppManager::Get(profile); |
| std::vector<api::autotest_private::SystemWebApp> result; |
| for (const auto& type_and_info : swa_manager->system_app_delegates()) { |
| api::autotest_private::SystemWebApp system_web_app; |
| ash::SystemWebAppDelegate* delegate = type_and_info.second.get(); |
| system_web_app.internal_name = delegate->GetInternalName(); |
| system_web_app.url = |
| delegate->GetInstallUrl().DeprecatedGetOriginAsURL().spec(); |
| system_web_app.name = base::UTF16ToUTF8(delegate->GetWebAppInfo()->title); |
| |
| absl::optional<web_app::AppId> app_id = |
| swa_manager->GetAppIdForSystemApp(type_and_info.first); |
| if (app_id) { |
| system_web_app.start_url = |
| ash::SystemWebAppManager::GetWebAppProvider(profile) |
| ->registrar_unsafe() |
| .GetAppLaunchUrl(*app_id) |
| .spec(); |
| } |
| result.push_back(std::move(system_web_app)); |
| } |
| |
| Respond(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()); |
| ash::SystemWebAppManager* swa_manager = |
| ash::SystemWebAppManager::Get(profile); |
| |
| if (!swa_manager) |
| return RespondNow(Error("System 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; |
| |
| swa_manager->on_apps_synchronized().Post( |
| FROM_HERE, |
| base::BindOnce( |
| &AutotestPrivateIsSystemWebAppOpenFunction::OnSystemWebAppsInstalled, |
| this)); |
| return RespondLater(); |
| } |
| |
| void AutotestPrivateIsSystemWebAppOpenFunction::OnSystemWebAppsInstalled() { |
| Profile* profile = Profile::FromBrowserContext(browser_context()); |
| std::unique_ptr<api::autotest_private::IsSystemWebAppOpen::Params> params( |
| api::autotest_private::IsSystemWebAppOpen::Params::Create(args())); |
| absl::optional<ash::SystemWebAppType> app_type = |
| ash::GetSystemWebAppTypeForAppId(profile, params->app_id); |
| if (!app_type) { |
| Respond(Error("No system web app is found by given app id.")); |
| return; |
| } |
| |
| Respond(WithArguments(ash::FindSystemWebAppBrowser(profile, *app_type) != |
| nullptr)); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // 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_INTERNAL, |
| 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()); |
| ash::SystemWebAppManager* swa_manager = |
| ash::SystemWebAppManager::Get(profile); |
| |
| if (!swa_manager) |
| return RespondNow(Error("System Web Apps are not available for profile.")); |
| |
| swa_manager->on_apps_synchronized().Post( |
| FROM_HERE, |
| base::BindOnce( |
| &AutotestPrivateLaunchSystemWebAppFunction::OnSystemWebAppsInstalled, |
| this)); |
| return RespondLater(); |
| } |
| |
| void AutotestPrivateLaunchSystemWebAppFunction::OnSystemWebAppsInstalled() { |
| Profile* profile = Profile::FromBrowserContext(browser_context()); |
| ash::SystemWebAppManager* swa_manager = |
| ash::SystemWebAppManager::Get(profile); |
| |
| std::unique_ptr<api::autotest_private::LaunchSystemWebApp::Params> params( |
| api::autotest_private::LaunchSystemWebApp::Params::Create(args())); |
| absl::optional<ash::SystemWebAppType> app_type; |
| |
| for (const auto& type_and_info : swa_manager->system_app_delegates()) { |
| if (type_and_info.second->GetInternalName() == params->app_name) { |
| app_type = type_and_info.first; |
| break; |
| } |
| } |
| if (!app_type.has_value()) { |
| Respond(Error("No mapped system web app found")); |
| return; |
| } |
| |
| ash::SystemAppLaunchParams swa_params; |
| swa_params.url = GURL(params->url); |
| ash::LaunchSystemWebAppAsync(profile, *app_type, swa_params); |
| |
| Respond(NoArguments()); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateLaunchFilesAppToPathFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateLaunchFilesAppToPathFunction:: |
| ~AutotestPrivateLaunchFilesAppToPathFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| AutotestPrivateLaunchFilesAppToPathFunction::Run() { |
| std::unique_ptr<api::autotest_private::LaunchFilesAppToPath::Params> params( |
| api::autotest_private::LaunchFilesAppToPath::Params::Create(args())); |
| EXTENSION_FUNCTION_VALIDATE(params); |
| |
| base::FilePath absolute_path(params->absolute_path); |
| if (!absolute_path.IsAbsolute()) { |
| return RespondNow(Error("Supplied path is not absolute")); |
| } |
| |
| Profile* profile = Profile::FromBrowserContext(browser_context()); |
| file_manager::util::ShowItemInFolder( |
| profile, std::move(absolute_path), |
| base::BindOnce( |
| &AutotestPrivateLaunchFilesAppToPathFunction::OnShowItemInFolder, |
| this)); |
| |
| return RespondLater(); |
| } |
| |
| void AutotestPrivateLaunchFilesAppToPathFunction::OnShowItemInFolder( |
| platform_util::OpenOperationResult result) { |
| if (result != platform_util::OpenOperationResult::OPEN_SUCCEEDED) { |
| DVLOG(1) << "Failed navigating to folder with error: " << result; |
| Respond(Error("Failed trying to open the supplied path")); |
| return; |
| } |
| |
| Respond(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(WithArguments(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. |
| ash::CrostiniInstallerDialog::Show( |
| profile, |
| base::BindOnce([](base::WeakPtr<ash::CrostiniInstallerUI> installer_ui) { |
| installer_ui->ClickInstallForTesting(); |
| })); |
| crostini::CrostiniManager::GetForProfile(profile)->RestartCrostini( |
| crostini::DefaultContainerId(), |
| 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::DefaultContainerId(), |
| 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::DefaultContainerId(), |
| file_manager::util::GetDownloadsFolderForProfile(profile).Append(path), |
| base::BindOnce(&AutotestPrivateImportCrostiniFunction::CrostiniImported, |
| this)); |
| |
| return RespondLater(); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateCouldAllowCrostiniFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateCouldAllowCrostiniFunction:: |
| ~AutotestPrivateCouldAllowCrostiniFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| AutotestPrivateCouldAllowCrostiniFunction::Run() { |
| DVLOG(1) << "AutotestPrivateCouldAllowCrostiniFunction"; |
| |
| Profile* profile = Profile::FromBrowserContext(browser_context()); |
| return RespondNow(WithArguments( |
| crostini::CrostiniFeatures::Get()->CouldBeAllowed(profile))); |
| } |
| |
| 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(std::string)> completion_callback) |
| : observation_(this), |
| completion_callback_(std::move(completion_callback)) { |
| observation_.Observe( |
| &borealis::BorealisService::GetForProfile(profile)->Installer()); |
| base::SequencedTaskRunner::GetCurrentDefault()->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, |
| const std::string& error_description) override { |
| std::move(completion_callback_) |
| .Run(result == borealis::BorealisInstallResult::kSuccess |
| ? "" |
| : "Failed to install Borealis: " + error_description); |
| } |
| |
| void OnCancelInitiated() override {} |
| |
| private: |
| base::ScopedObservation<borealis::BorealisInstaller, |
| borealis::BorealisInstaller::Observer> |
| observation_; |
| base::OnceCallback<void(std::string)> 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( |
| std::string error_or_empty) { |
| if (error_or_empty.empty()) { |
| Respond(NoArguments()); |
| } else { |
| Respond(Error(error_or_empty)); |
| } |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // 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(WithArguments(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(WithArguments(GetPngDataAsString(png_data))); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateGetPrinterListFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateGetPrinterListFunction::AutotestPrivateGetPrinterListFunction() = |
| default; |
| |
| 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_ = ash::CupsPrintersManager::Create(profile); |
| printers_manager_->AddObserver(this); |
| |
| // Set up a timer to finish waiting after 10 seconds |
| timeout_timer_.Start( |
| FROM_HERE, base::Seconds(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(WithArguments(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::Dict result; |
| result.Set("printerName", printer.display_name()); |
| result.Set("printerId", printer.id()); |
| result.Set("printerType", 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::SingleThreadTaskRunner::GetCurrentDefault()->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 = |
| ash::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 = |
| ash::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")); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateLoadSmartDimComponentFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateLoadSmartDimComponentFunction:: |
| AutotestPrivateLoadSmartDimComponentFunction() = default; |
| AutotestPrivateLoadSmartDimComponentFunction:: |
| ~AutotestPrivateLoadSmartDimComponentFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| AutotestPrivateLoadSmartDimComponentFunction::Run() { |
| DVLOG(1) << "AutotestPrivateLoadSmartDimComponentFunction"; |
| |
| if (ash::power::ml::SmartDimMlAgent::GetInstance()->IsDownloadWorkerReady()) { |
| return RespondNow(NoArguments()); |
| } |
| |
| const std::string crx_id = |
| component_updater::SmartDimComponentInstallerPolicy::GetExtensionId(); |
| g_browser_process->component_updater()->GetOnDemandUpdater().OnDemandUpdate( |
| crx_id, component_updater::OnDemandUpdater::Priority::FOREGROUND, |
| base::BindOnce(&AutotestPrivateLoadSmartDimComponentFunction:: |
| OnComponentUpdatedCallback, |
| this)); |
| |
| timer_.Start( |
| FROM_HERE, base::Seconds(5), |
| base::BindRepeating( |
| &AutotestPrivateLoadSmartDimComponentFunction::TryRespond, this)); |
| |
| return RespondLater(); |
| } |
| |
| void AutotestPrivateLoadSmartDimComponentFunction::OnComponentUpdatedCallback( |
| update_client::Error error) { |
| if (error != update_client::Error::NONE && |
| error != update_client::Error::UPDATE_IN_PROGRESS) { |
| Respond(Error(base::StringPrintf( |
| "On demand update of the SmartDim component failed with error: %d.", |
| static_cast<int>(error)))); |
| } |
| } |
| |
| void AutotestPrivateLoadSmartDimComponentFunction::TryRespond() { |
| ++timer_triggered_count_; |
| if (did_respond()) { |
| return; |
| } |
| |
| if (ash::power::ml::SmartDimMlAgent::GetInstance()->IsDownloadWorkerReady()) { |
| Respond(NoArguments()); |
| } else if (timer_triggered_count_ >= 12) { |
| Respond(Error("Timeout occurred before SmartDim component was loaded.")); |
| } else { |
| timer_.Reset(); |
| } |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // 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 = |
| SetAllowedPref(profile, ash::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() == |
| ash::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::Milliseconds(params->timeout_ms), |
| base::BindOnce(&AutotestPrivateSetAssistantEnabledFunction::Timeout, |
| this)); |
| return RespondLater(); |
| } |
| |
| void AutotestPrivateSetAssistantEnabledFunction::OnAssistantStatusChanged( |
| ash::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 == ash::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() = default; |
| |
| ExtensionFunction::ResponseAction |
| AutotestPrivateEnableAssistantAndWaitForReadyFunction::Run() { |
| DVLOG(1) << "AutotestPrivateEnableAssistantAndWaitForReadyFunction"; |
| |
| if (ash::AssistantState::Get()->assistant_status() == |
| ash::assistant::AssistantStatus::READY) { |
| return RespondNow(Error("Assistant is already enabled.")); |
| } |
| |
| // We can set this callback only when assistant status is NOT_READY. We should |
| // call this before we try to enable Assistant to avoid causing some timing |
| // issue. |
| ash::assistant::AssistantManagerServiceImpl:: |
| SetInitializedInternalCallbackForTesting(base::BindOnce( |
| &AutotestPrivateEnableAssistantAndWaitForReadyFunction:: |
| OnInitializedInternal, |
| this)); |
| |
| Profile* profile = Profile::FromBrowserContext(browser_context()); |
| const std::string& err_msg = SetAllowedPref( |
| profile, ash::assistant::prefs::kAssistantEnabled, base::Value(true)); |
| if (!err_msg.empty()) |
| return RespondNow(Error(err_msg)); |
| |
| return RespondLater(); |
| } |
| |
| void AutotestPrivateEnableAssistantAndWaitForReadyFunction:: |
| OnInitializedInternal() { |
| Respond(NoArguments()); |
| } |
| |
| // 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 ash::assistant::AssistantInteractionSubscriber { |
| public: |
| using OnInteractionFinishedCallback = |
| base::OnceCallback<void(const absl::optional<std::string>& error)>; |
| |
| AssistantInteractionHelper() = default; |
| |
| AssistantInteractionHelper(const AssistantInteractionHelper&) = delete; |
| AssistantInteractionHelper& operator=(const AssistantInteractionHelper&) = |
| delete; |
| |
| ~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, ash::assistant::AssistantQuerySource::kUnspecified, allow_tts); |
| |
| query_status_.Set("queryText", query); |
| } |
| |
| base::Value::Dict GetQueryStatus() { return std::move(query_status_); } |
| |
| ash::assistant::Assistant* GetAssistant() { |
| auto* assistant_service = ash::assistant::AssistantService::Get(); |
| return assistant_service ? assistant_service->GetAssistant() : nullptr; |
| } |
| |
| private: |
| // ash::assistant::AssistantInteractionSubscriber: |
| using AssistantSuggestion = ash::assistant::AssistantSuggestion; |
| using AssistantInteractionMetadata = |
| ash::assistant::AssistantInteractionMetadata; |
| using AssistantInteractionResolution = |
| ash::assistant::AssistantInteractionResolution; |
| |
| void OnInteractionStarted( |
| const AssistantInteractionMetadata& metadata) override { |
| const bool is_voice_interaction = |
| ash::assistant::AssistantInteractionType::kVoice == metadata.type; |
| query_status_.Set("isMicOpen", is_voice_interaction); |
| interaction_in_progress_ = true; |
| } |
| |
| void OnInteractionFinished( |
| AssistantInteractionResolution resolution) override { |
| // If you send an Assistant text query while another query is already |
| // running, OnInteractionFinished can be called for it. We have to subscribe |
| // assistant interactions before sending a text query as it can trigger |
| // OnInteractionStarted. |
| // |
| // e.g. |
| // 1. autotestPrivate.sendAssistantTextQuery("your query", ...). |
| // 2. AutoTestPrivate starts listening Assistant interactions. |
| // 3. AutoTestPrivate sends the text query to Assistant. |
| // 4. Assistant cancels the on-going query. -> OnInteractionFinished |
| // 5. Assistant starts the new query. -> OnInteractionStarted |
| if (!interaction_in_progress_) { |
| DVLOG(1) << "Ignoring an uninterested OnInteractionFinished call"; |
| return; |
| } |
| |
| interaction_in_progress_ = false; |
| |
| CHECK(on_interaction_finished_callback_) |
| << "on_interaction_finished_callback_ is not set."; |
| |
| if (resolution != AssistantInteractionResolution::kNormal) { |
| SendErrorResponse( |
| base::StringPrintf("Interaction closed with resolution %s", |
| ResolutionToString(resolution).c_str())); |
| return; |
| } |
| |
| // 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_.empty()) |
| return; |
| |
| query_status_.Set("queryResponse", std::move(result_)); |
| SendSuccessResponse(); |
| } |
| |
| void OnHtmlResponse(const std::string& response, |
| const std::string& fallback) override { |
| result_.Set("htmlResponse", response); |
| CheckResponseIsValid(__FUNCTION__); |
| } |
| |
| void OnTextResponse(const std::string& response) override { |
| result_.Set("text", response); |
| CheckResponseIsValid(__FUNCTION__); |
| } |
| |
| void OnOpenUrlResponse(const ::GURL& url, bool in_background) override { |
| result_.Set("openUrl", url.possibly_invalid_spec()); |
| } |
| |
| void OnOpenAppResponse( |
| const ash::assistant::AndroidAppInfo& app_info) override { |
| result_.Set("openAppResponse", app_info.package_name); |
| CheckResponseIsValid(__FUNCTION__); |
| } |
| |
| void OnSpeechRecognitionFinalResult( |
| const std::string& final_result) override { |
| query_status_.Set("queryText", 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); |
| } |
| |
| base::Value::Dict query_status_; |
| base::Value::Dict result_; |
| bool interaction_in_progress_ = false; |
| |
| // Callback triggered when interaction finished with non-empty response. |
| OnInteractionFinishedCallback on_interaction_finished_callback_; |
| }; |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // 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()); |
| ash::assistant::AssistantAllowedState allowed_state = |
| assistant::IsAssistantAllowedForProfile(profile); |
| if (allowed_state != ash::assistant::AssistantAllowedState::ALLOWED) { |
| return RespondNow(Error(base::StringPrintf( |
| "Assistant not allowed - state: %d", allowed_state))); |
| } |
| |
| session_manager::SessionState session_state = |
| session_manager::SessionManager::Get()->session_state(); |
| if (session_state != session_manager::SessionState::ACTIVE) { |
| // tast side code matches with this error string, i.e. update both if you |
| // change this. |
| return RespondNow( |
| Error("Session state must be ACTIVE to send a text query. Session " |
| "state was *", |
| ToString(session_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::Milliseconds(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(WithArguments(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(); |
| } |
| |
| std::string AutotestPrivateSendAssistantTextQueryFunction::ToString( |
| session_manager::SessionState session_state) { |
| switch (session_state) { |
| case session_manager::SessionState::UNKNOWN: |
| return "UNKNOWN"; |
| case session_manager::SessionState::OOBE: |
| return "OOBE"; |
| case session_manager::SessionState::LOGIN_PRIMARY: |
| return "LOGIN_PRIMARY"; |
| case session_manager::SessionState::LOGGED_IN_NOT_ACTIVE: |
| return "LOGGED_IN_NOT_ACTIVE"; |
| case session_manager::SessionState::ACTIVE: |
| return "ACTIVE"; |
| case session_manager::SessionState::LOCKED: |
| return "LOCKED"; |
| case session_manager::SessionState::LOGIN_SECONDARY: |
| return "LOGIN_SECONDARY"; |
| case session_manager::SessionState::RMA: |
| return "RMA"; |
| } |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // 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()); |
| ash::assistant::AssistantAllowedState allowed_state = |
| assistant::IsAssistantAllowedForProfile(profile); |
| if (allowed_state != ash::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::Seconds(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(WithArguments(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(WithArguments(prefs->package_list_initial_refreshed())); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateSetAllowedPrefFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateSetAllowedPrefFunction:: |
| ~AutotestPrivateSetAllowedPrefFunction() = default; |
| |
| ExtensionFunction::ResponseAction AutotestPrivateSetAllowedPrefFunction::Run() { |
| DVLOG(1) << "AutotestPrivateSetAllowedPrefFunction"; |
| |
| std::unique_ptr<api::autotest_private::SetAllowedPref::Params> params( |
| api::autotest_private::SetAllowedPref::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 = SetAllowedPref(profile, pref_name, value); |
| |
| if (!err_msg.empty()) |
| return RespondNow(Error(err_msg)); |
| |
| return RespondNow(NoArguments()); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateSetWhitelistedPrefFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateSetWhitelistedPrefFunction:: |
| ~AutotestPrivateSetWhitelistedPrefFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| AutotestPrivateSetWhitelistedPrefFunction::Run() { |
| DVLOG(1) << "AutotestPrivateSetWhitelistedPrefFunction"; |
| |
| std::unique_ptr<api::autotest_private::SetAllowedPref::Params> params( |
| api::autotest_private::SetAllowedPref::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 = SetAllowedPref(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(WithArguments(scale_factor)); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateIsTabletModeEnabledFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateIsTabletModeEnabledFunction:: |
| ~AutotestPrivateIsTabletModeEnabledFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| AutotestPrivateIsTabletModeEnabledFunction::Run() { |
| DVLOG(1) << "AutotestPrivateIsTabletModeEnabledFunction"; |
| |
| return RespondNow(WithArguments(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(WithArguments(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(WithArguments(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::AppServiceProxy* proxy = |
| apps::AppServiceProxyFactory::GetForProfile(profile); |
| |
| std::vector<api::autotest_private::App> installed_apps; |
| proxy->AppRegistryCache().ForEachApp([&installed_apps]( |
| const apps::AppUpdate& update) { |
| if (!apps_util::IsInstalled(update.Readiness())) |
| return; |
| |
| api::autotest_private::App app; |
| app.app_id = update.AppId(); |
| |
| // Assume that when `switches::kForceDirectionRTL` is enabled, the system |
| // language still follows the left-to-right fashion. Because the app names |
| // carried by `update` are adapted to RTL by inserting extra characters that |
| // indicate the text direction, we should recover the original app names |
| // before returning them as the result. |
| if (base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII( |
| switches::kForceUIDirection) == switches::kForceDirectionRTL) { |
| std::u16string name = base::UTF8ToUTF16(update.Name()); |
| base::i18n::UnadjustStringForLocaleDirection(&name); |
| app.name = base::UTF16ToUTF8(name); |
| } else { |
| 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.InstallReason()); |
| app.readiness = GetAppReadiness(update.Readiness()); |
| app.show_in_launcher = update.ShowInLauncher(); |
| app.show_in_search = 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))); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateGetLauncherSearchBoxStateFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateGetLauncherSearchBoxStateFunction:: |
| AutotestPrivateGetLauncherSearchBoxStateFunction() = default; |
| |
| AutotestPrivateGetLauncherSearchBoxStateFunction:: |
| ~AutotestPrivateGetLauncherSearchBoxStateFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| AutotestPrivateGetLauncherSearchBoxStateFunction::Run() { |
| DVLOG(1) << "AutotestPrivateGetLauncherSearchBoxStateFunction"; |
| |
| api::autotest_private::LauncherSearchBoxState launcher_search_box_state; |
| launcher_search_box_state.ghost_text = ash::GetSearchBoxGhostTextForTest(); |
| |
| return RespondNow(WithArguments(launcher_search_box_state.ToValue())); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // 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(WithArguments(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( |
| WithArguments(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()); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateSendArcOverlayColorFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateSendArcOverlayColorFunction:: |
| ~AutotestPrivateSendArcOverlayColorFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| AutotestPrivateSendArcOverlayColorFunction::Run() { |
| DVLOG(1) << "AutotestPrivateSendArcOverlayColorFunction"; |
| std::unique_ptr<api::autotest_private::SendArcOverlayColor::Params> params( |
| api::autotest_private::SendArcOverlayColor::Params::Create(args())); |
| EXTENSION_FUNCTION_VALIDATE(params); |
| arc::ArcSystemUIBridge* const system_ui = |
| arc::ArcSystemUIBridge::GetForBrowserContext(browser_context()); |
| if (!system_ui) |
| return RespondNow(Error("No ARC System UI Bridge is available.")); |
| const bool result = system_ui->SendOverlayColor( |
| params->color, ToThemeStyleType(params->theme)); |
| return RespondNow(WithArguments(result)); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // 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 = WithArguments(finished); |
| // On starting the overview animation, it needs to wait for 1 extra second |
| // to trigger the occlusion tracker. |
| if (for_start) { |
| base::SequencedTaskRunner::GetCurrentDefault()->PostDelayedTask( |
| FROM_HERE, |
| base::BindOnce(&AutotestPrivateSetOverviewModeStateFunction::Respond, |
| this, std::move(arg)), |
| base::Seconds(1)); |
| } else { |
| Respond(std::move(arg)); |
| } |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateGetDefaultPinnedAppIdsFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateGetDefaultPinnedAppIdsFunction:: |
| AutotestPrivateGetDefaultPinnedAppIdsFunction() = default; |
| |
| AutotestPrivateGetDefaultPinnedAppIdsFunction:: |
| ~AutotestPrivateGetDefaultPinnedAppIdsFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| AutotestPrivateGetDefaultPinnedAppIdsFunction::Run() { |
| std::vector<std::string> default_pinned_app_ids; |
| for (const char* default_app_id : GetDefaultPinnedAppsForFormFactor()) |
| default_pinned_app_ids.emplace_back(default_app_id); |
| |
| return RespondNow(ArgumentList( |
| api::autotest_private::GetDefaultPinnedAppIds::Results::Create( |
| default_pinned_app_ids))); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateShowVirtualKeyboardIfEnabledFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateShowVirtualKeyboardIfEnabledFunction:: |
| AutotestPrivateShowVirtualKeyboardIfEnabledFunction() = default; |
| AutotestPrivateShowVirtualKeyboardIfEnabledFunction:: |
| ~AutotestPrivateShowVirtualKeyboardIfEnabledFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| AutotestPrivateShowVirtualKeyboardIfEnabledFunction::Run() { |
| if (!ash::IMEBridge::Get() || |
| !ash::IMEBridge::Get()->GetInputContextHandler() || |
| !ash::IMEBridge::Get()->GetInputContextHandler()->GetInputMethod()) { |
| return RespondNow(NoArguments()); |
| } |
| |
| ash::IMEBridge::Get() |
| ->GetInputContextHandler() |
| ->GetInputMethod() |
| ->SetVirtualKeyboardVisibilityIfEnabled(true); |
| 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) { |
| base::Value::Dict result; |
| result.Set("success", success); |
| result.Set("fps", fps); |
| result.Set("commitDeviation", commit_deviation); |
| result.Set("renderQuality", render_quality); |
| Respond(WithArguments(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(WithArguments(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 WithArguments(!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()); |
| // Check for window hiding animations separately because they pertain to |
| // layers detached from the window. |
| window_info.is_animating = |
| window->layer()->GetAnimator()->is_animating() || |
| window->GetProperty(wm::kWindowHidingAnimationCountKey) > 0; |
| 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 = |
| chromeos::DesksHelper::Get(window)->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 = *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* full_restore_window_app_id = |
| window->GetProperty(app_restore::kAppIdKey); |
| if (full_restore_window_app_id) { |
| window_info.full_restore_window_app_id = *full_restore_window_app_id; |
| } |
| std::string* app_id = window->GetProperty(ash::kAppIDKey); |
| if (app_id) |
| window_info.app_id = *app_id; |
| |
| auto* widget = views::Widget::GetWidgetForNativeWindow(window); |
| // Frame information |
| auto* immersive_controller = |
| chromeos::ImmersiveFullscreenController::Get(widget); |
| |
| // 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. |
| if (immersive_controller) |
| widget = immersive_controller->widget(); |
| |
| if (immersive_controller && 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); |
| if (frame_header) { |
| 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_TOP_SNAPPED, |
| views::CAPTION_BUTTON_ICON_RIGHT_BOTTOM_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* no_frame_header_widget = |
| views::Widget::GetWidgetForNativeWindow(window); |
| // All widgets for app windows in chromeos should have a frame. Non app |
| // windows may not have a frame and frame mode will be NONE. |
| DCHECK(!no_frame_header_widget || |
| no_frame_header_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.emplace(); |
| 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(WithArguments( |
| api::autotest_private::ToString(ToWindowStateType(expected_state)))); |
| } |
| } |
| |
| const bool wait = params->wait && *params->wait; |
| |
| if (wait) { |
| window_state_observer_ = std::make_unique<WindowStateChangeObserver>( |
| window, expected_state, |
| base::BindOnce( |
| &AutotestPrivateSetAppWindowStateFunction::WindowStateChanged, this, |
| expected_state)); |
| } |
| |
| if (params->change.event_type == |
| api::autotest_private::WMEventType::WM_EVENT_TYPE_WMEVENTSNAPLEFT || |
| params->change.event_type == |
| api::autotest_private::WMEventType::WM_EVENT_TYPE_WMEVENTSNAPRIGHT) { |
| const ash::WMEvent event(ToWMEventType(params->change.event_type)); |
| ash::WindowState::Get(window)->OnWMEvent(&event); |
| } else { |
| const ash::WMEvent event(ToWMEventType(params->change.event_type)); |
| ash::WindowState::Get(window)->OnWMEvent(&event); |
| } |
| |
| if (!wait) { |
| return RespondNow(WithArguments( |
| api::autotest_private::ToString(ToWindowStateType(expected_state)))); |
| } |
| |
| 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(WithArguments( |
| 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 PWA. |
| 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::kYes_Promotable || |
| installable == Installable::kYes_ByUserRequest) { |
| observation_.Reset(); |
| std::move(callback_).Run(); |
| } |
| } |
| |
| PWABannerObserver(const PWABannerObserver&) = delete; |
| PWABannerObserver& operator=(const PWABannerObserver&) = delete; |
| |
| ~PWABannerObserver() override {} |
| |
| void OnInstallableWebAppStatusUpdated() override { |
| Installable installable = |
| app_banner_manager_->GetInstallableWebAppCheckResultForTesting(); |
| switch (installable) { |
| case Installable::kNo: |
| [[fallthrough]]; |
| case Installable::kNo_AlreadyInstalled: |
| [[fallthrough]]; |
| case Installable::kUnknown: |
| DCHECK(false) << "Unexpected AppBannerManager::Installable value (kNo " |
| "or kNoAlreadyInstalled or kUnknown)"; |
| break; |
| |
| case Installable::kYes_Promotable: |
| [[fallthrough]]; |
| case Installable::kYes_ByUserRequest: |
| 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_; |
| }; |
| |
| // Used to notify when a PWA is installed. |
| class AutotestPrivateInstallPWAForCurrentURLFunction::PWAInstallManagerObserver |
| : public web_app::WebAppInstallManagerObserver { |
| public: |
| PWAInstallManagerObserver( |
| Profile* profile, |
| base::OnceCallback<void(const web_app::AppId&)> callback) |
| : provider_(web_app::WebAppProvider::GetForWebApps(profile)), |
| callback_(std::move(callback)) { |
| if (!provider_) |
| return; |
| provider_->on_registry_ready().Post( |
| FROM_HERE, |
| base::BindOnce(&AutotestPrivateInstallPWAForCurrentURLFunction:: |
| PWAInstallManagerObserver::OnProviderReady, |
| weak_factory_.GetWeakPtr())); |
| } |
| |
| PWAInstallManagerObserver(const PWAInstallManagerObserver&) = delete; |
| PWAInstallManagerObserver& operator=(const PWAInstallManagerObserver&) = |
| delete; |
| |
| ~PWAInstallManagerObserver() override {} |
| |
| void OnProviderReady() { |
| observation_.Observe(&provider_->install_manager()); |
| } |
| |
| void OnWebAppInstalled(const web_app::AppId& app_id) override { |
| observation_.Reset(); |
| std::move(callback_).Run(app_id); |
| } |
| |
| void OnWebAppInstallManagerDestroyed() override { observation_.Reset(); } |
| |
| private: |
| base::ScopedObservation<web_app::WebAppInstallManager, |
| web_app::WebAppInstallManagerObserver> |
| observation_{this}; |
| web_app::WebAppProvider* provider_; |
| base::OnceCallback<void(const web_app::AppId&)> callback_; |
| base::WeakPtrFactory< |
| AutotestPrivateInstallPWAForCurrentURLFunction::PWAInstallManagerObserver> |
| weak_factory_{this}; |
| }; |
| |
| 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::Milliseconds(params->timeout_ms), |
| base::BindOnce( |
| &AutotestPrivateInstallPWAForCurrentURLFunction::PWATimeout, this)); |
| return RespondLater(); |
| } |
| |
| void AutotestPrivateInstallPWAForCurrentURLFunction::PWALoaded() { |
| Profile* profile = Profile::FromBrowserContext(browser_context()); |
| Browser* browser = GetFirstRegularBrowser(); |
| |
| install_mananger_observer_ = std::make_unique<PWAInstallManagerObserver>( |
| 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(WithArguments(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(WithArguments(result)); |
| } |
| bool result = accelerator_controller->Process(accelerator); |
| return RespondNow(WithArguments(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); |
| // The method is only implemented for fullscreen launcher, for bubble |
| // launcher, tests use automation APIs to wait for launcher visibility |
| // changes. |
| // Exceptionally, allow waiting for kClosed state in clamshell mode, so tests |
| // can wait for fullscreen launcher state change to finish when exiting tablet |
| // mode. |
| if (ash::features::IsProductivityLauncherEnabled() && |
| !ash::TabletMode::Get()->InTabletMode() && |
| target_state != ash::AppListViewState::kClosed) { |
| return RespondNow(Error("Not supported for bubble launcher")); |
| } |
| |
| 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(WithArguments(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(WithArguments(false)); |
| } |
| |
| return RespondLater(); |
| } |
| |
| void AutotestPrivateActivateDeskAtIndexFunction::OnAnimationComplete() { |
| Respond(WithArguments(true)); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateRemoveActiveDeskFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateRemoveActiveDeskFunction:: |
| AutotestPrivateRemoveActiveDeskFunction() = default; |
| AutotestPrivateRemoveActiveDeskFunction:: |
| ~AutotestPrivateRemoveActiveDeskFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| AutotestPrivateRemoveActiveDeskFunction::Run() { |
| // Check whether overview mode is active before removing the desk. In case of |
| // split view, the desk removal may cause overview to end, but what matters is |
| // whether overview mode is active before. |
| const bool in_overview = |
| ash::Shell::Get()->overview_controller()->InOverviewSession(); |
| |
| if (!ash::AutotestDesksApi().RemoveActiveDesk(base::BindOnce( |
| &AutotestPrivateRemoveActiveDeskFunction::OnAnimationComplete, |
| this))) { |
| return RespondNow(WithArguments(false)); |
| } |
| |
| // In overview, the desk removal animation does |
| // not apply, so we should not wait for it. |
| if (in_overview) |
| return RespondNow(WithArguments(true)); |
| return RespondLater(); |
| } |
| |
| void AutotestPrivateRemoveActiveDeskFunction::OnAnimationComplete() { |
| Respond(WithArguments(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(WithArguments(false)); |
| } |
| |
| return RespondLater(); |
| } |
| |
| void AutotestPrivateActivateAdjacentDesksToTargetIndexFunction:: |
| OnAnimationComplete() { |
| Respond(WithArguments(true)); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateGetDeskCountFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateGetDeskCountFunction::AutotestPrivateGetDeskCountFunction() = |
| default; |
| AutotestPrivateGetDeskCountFunction::~AutotestPrivateGetDeskCountFunction() = |
| default; |
| |
| ExtensionFunction::ResponseAction AutotestPrivateGetDeskCountFunction::Run() { |
| return RespondNow( |
| WithArguments(ash::AutotestDesksApi().GetDesksInfo().num_desks)); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateGetDesksInfoFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateGetDesksInfoFunction::AutotestPrivateGetDesksInfoFunction() = |
| default; |
| AutotestPrivateGetDesksInfoFunction::~AutotestPrivateGetDesksInfoFunction() = |
| default; |
| |
| ExtensionFunction::ResponseAction AutotestPrivateGetDesksInfoFunction::Run() { |
| ash::AutotestDesksApi::DesksInfo desks_info = |
| ash::AutotestDesksApi().GetDesksInfo(); |
| base::Value::Dict result; |
| result.Set("activeDeskIndex", desks_info.active_desk_index); |
| result.Set("numDesks", desks_info.num_desks); |
| result.Set("isAnimating", desks_info.is_animating); |
| |
| base::Value::List desk_containers; |
| for (std::string& desk_container : desks_info.desk_containers) |
| desk_containers.Append(std::move(desk_container)); |
| result.Set("deskContainers", std::move(desk_containers)); |
| |
| return RespondNow(WithArguments(std::move(result))); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // 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(ash::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(ash::kStatsReportingPref, |
| &actual)) { |
| NOTREACHED() << "AutotestPrivateSetMetricsEnabledFunction: " |
| << "kStatsReportingPref should be set"; |
| Respond(Error(base::StrCat({"Failed to set metrics consent: ", |
| ash::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: ", ash::kStatsReportingPref, |
| " has wrong 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")); |
| |
| PinAppWithIDToShelf(params->app_id); |
| return RespondNow(NoArguments()); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateSetShelfIconPinFunction |
| //////////////////////////////////////////////////////////////////////////////// |
| AutotestPrivateSetShelfIconPinFunction:: |
| AutotestPrivateSetShelfIconPinFunction() = default; |
| AutotestPrivateSetShelfIconPinFunction:: |
| ~AutotestPrivateSetShelfIconPinFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| AutotestPrivateSetShelfIconPinFunction::Run() { |
| std::unique_ptr<api::autotest_private::SetShelfIconPin::Params> params( |
| api::autotest_private::SetShelfIconPin::Params::Create(args())); |
| |
| ChromeShelfController* const controller = ChromeShelfController::instance(); |
| if (!controller) |
| return RespondNow(Error("Controller not available")); |
| |
| const std::vector<api::autotest_private::ShelfIconPinUpdateParam>& |
| update_params = params->update_params; |
| |
| // Save the app IDs causing errors. |
| std::vector<std::string> problematic_app_ids; |
| |
| for (const auto& update_param : update_params) { |
| const std::string& app_id = update_param.app_id; |
| if (!controller->AllowedToSetAppPinState(app_id, update_param.pinned)) |
| problematic_app_ids.push_back(app_id); |
| } |
| |
| if (!problematic_app_ids.empty()) { |
| return RespondNow( |
| Error(base::StrCat({"Unable to update pin state: ", |
| base::JoinString(problematic_app_ids, ",")}))); |
| } |
| |
| // Save the ids of the apps whose pin states are updated. Note that the apps |
| // which reach the target pin states before api function execution are not |
| // included in `updated_apps`. |
| std::vector<std::string> updated_apps; |
| |
| for (const auto& update_param : update_params) { |
| const std::string& app_id = update_param.app_id; |
| |
| // Already reach the target pin state. No op. |
| if (update_param.pinned == controller->IsAppPinned(app_id)) |
| continue; |
| |
| if (update_param.pinned) |
| PinAppWithIDToShelf(app_id); |
| else |
| UnpinAppWithIDFromShelf(app_id); |
| updated_apps.push_back(app_id); |
| } |
| |
| return RespondNow(ArgumentList( |
| api::autotest_private::SetShelfIconPin::Results::Create(updated_apps))); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // 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 = fetched_info.target_main_axis_offset; |
| } |
| |
| return RespondNow(WithArguments(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 = |
| 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); |
| hotseat_ui_info.is_auto_hidden = hotseat_info.is_auto_hidden; |
| |
| shelf_ui_info.hotseat_info = std::move(hotseat_ui_info); |
| } |
| |
| return RespondNow(WithArguments(shelf_ui_info.ToValue())); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateSetWindowBoundsFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateSetWindowBoundsFunction:: |
| AutotestPrivateSetWindowBoundsFunction() = default; |
| AutotestPrivateSetWindowBoundsFunction:: |
| ~AutotestPrivateSetWindowBoundsFunction() = default; |
| |
| namespace { |
| |
| base::Value::Dict BuildSetWindowBoundsResult(const gfx::Rect& bounds_in_display, |
| int64_t display_id) { |
| base::Value::Dict result; |
| result.Set("bounds", ToBoundsDictionary(bounds_in_display).ToValue()); |
| result.Set("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( |
| WithArguments(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(WithArguments( |
| 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* trackers = GetDisplaySmoothnessTrackers(); |
| if (trackers->find(display_id) != trackers->end()) { |
| return RespondNow( |
| Error(base::StrCat({"Smoothness already tracked for display: ", |
| base::NumberToString(display_id)}))); |
| } |
| |
| base::TimeDelta throughput_interval = kDefaultThroughputInterval; |
| if (params->throughput_interval_ms) |
| throughput_interval = base::Milliseconds(*params->throughput_interval_ms); |
| |
| auto tracker = std::make_unique<DisplaySmoothnessTracker>(); |
| if (!tracker->Start( |
| display_id, throughput_interval, |
| base::BindOnce(&ForwardFrameRateDataAndReset, display_id))) { |
| return RespondNow(Error(base::StrCat( |
| {"Invalid display_id; no root window found for the display id ", |
| base::NumberToString(display_id)}))); |
| } |
| (*trackers)[display_id] = 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* trackers = GetDisplaySmoothnessTrackers(); |
| auto it = trackers->find(display_id); |
| if (it == trackers->end()) { |
| return RespondNow( |
| Error(base::StrCat({"Smoothness is not tracked for display: ", |
| base::NumberToString(display_id)}))); |
| } |
| |
| if (it->second->stopping()) { |
| return RespondNow(Error( |
| base::StrCat({"stopSmoothnessTracking already called for display: ", |
| base::NumberToString(display_id)}))); |
| } |
| |
| const bool has_error = it->second->has_error(); |
| |
| // DisplaySmoothnessTracker::Stop does not invoke the report callback when |
| // gpu-process crashes and has no valid data to report. Start a timer to |
| // handle this case. |
| timeout_timer_.Start( |
| FROM_HERE, base::Seconds(5), |
| base::BindOnce(&AutotestPrivateStopSmoothnessTrackingFunction::OnTimeOut, |
| this, display_id)); |
| |
| it->second->Stop(base::BindOnce( |
| &AutotestPrivateStopSmoothnessTrackingFunction::OnReportData, this)); |
| |
| // Trigger a repaint after ThroughputTracker::Stop() to generate a frame to |
| // ensure the tracker report will be sent back. |
| auto* root_window = ash::Shell::GetRootWindowForDisplayId(display_id); |
| root_window->GetHost()->compositor()->ScheduleFullRedraw(); |
| |
| if (has_error) { |
| return RespondNow(Error(base::StrCat( |
| {"Error happened during smoothness collection for display: ", |
| base::NumberToString(display_id)}))); |
| } |
| |
| return did_respond() ? AlreadyResponded() : RespondLater(); |
| } |
| |
| void AutotestPrivateStopSmoothnessTrackingFunction::OnReportData( |
| const cc::FrameSequenceMetrics::CustomReportData& frame_data, |
| std::vector<int>&& throughput) { |
| if (did_respond()) |
| return; |
| |
| timeout_timer_.AbandonAndStop(); |
| |
| api::autotest_private::DisplaySmoothnessData result_data; |
| result_data.frames_expected = frame_data.frames_expected; |
| result_data.frames_produced = frame_data.frames_produced; |
| result_data.jank_count = frame_data.jank_count; |
| result_data.throughput = std::move(throughput); |
| |
| Respond(ArgumentList( |
| api::autotest_private::StopSmoothnessTracking::Results::Create( |
| result_data))); |
| } |
| |
| void AutotestPrivateStopSmoothnessTrackingFunction::OnTimeOut( |
| int64_t display_id) { |
| if (did_respond()) |
| return; |
| |
| // Clean up the non-functional tracker. |
| auto* trackers = GetDisplaySmoothnessTrackers(); |
| auto it = trackers->find(display_id); |
| if (it == trackers->end()) |
| return; |
| trackers->erase(it); |
| |
| Respond(Error("Smoothness is not available")); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // 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::Seconds(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() { |
| // This disables accessibility for Chrome Views. |
| AutomationManagerAura::GetInstance()->Disable(); |
| |
| // This disables accessibility for all other accessibility trees including |
| // ARC++, Ash web contents. |
| AutomationEventRouter::GetInstance() |
| ->UnregisterAllListenersWithDesktopPermission(); |
| AutomationEventRouter::GetInstance()->NotifyAllAutomationExtensionsGone(); |
| |
| // Finally, this disables accessibility in Lacros. |
| crosapi::CrosapiManager::Get() |
| ->crosapi_ash() |
| ->automation_ash() |
| ->AllAutomationExtensionsGone(); |
| |
| return RespondNow(NoArguments()); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateStartThroughputTrackerDataCollectionFunction |
| ////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateStartThroughputTrackerDataCollectionFunction:: |
| AutotestPrivateStartThroughputTrackerDataCollectionFunction() = default; |
| |
| AutotestPrivateStartThroughputTrackerDataCollectionFunction:: |
| ~AutotestPrivateStartThroughputTrackerDataCollectionFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| AutotestPrivateStartThroughputTrackerDataCollectionFunction::Run() { |
| g_last_start_throughput_data_collection_tick = base::TimeTicks::Now(); |
| 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; |
| result_data.reserve(collected_data.size()); |
| for (const auto& data : collected_data) { |
| api::autotest_private::ThroughputTrackerAnimationData animation_data; |
| animation_data.start_offset_ms = |
| (data.start_tick - g_last_start_throughput_data_collection_tick) |
| .InMilliseconds(); |
| animation_data.stop_offset_ms = |
| (data.stop_tick - g_last_start_throughput_data_collection_tick) |
| .InMilliseconds(); |
| animation_data.frames_expected = data.smoothness_data.frames_expected; |
| animation_data.frames_produced = data.smoothness_data.frames_produced; |
| animation_data.jank_count = data.smoothness_data.jank_count; |
| result_data.emplace_back(std::move(animation_data)); |
| } |
| return RespondNow( |
| ArgumentList(api::autotest_private::StopThroughputTrackerDataCollection:: |
| Results::Create(result_data))); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateGetThroughputTrackerDataFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| AutotestPrivateGetThroughputTrackerDataFunction:: |
| AutotestPrivateGetThroughputTrackerDataFunction() = default; |
| |
| AutotestPrivateGetThroughputTrackerDataFunction:: |
| ~AutotestPrivateGetThroughputTrackerDataFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| AutotestPrivateGetThroughputTrackerDataFunction::Run() { |
| auto collected_data = ash::metrics_util::GetCollectedData(); |
| std::vector<api::autotest_private::ThroughputTrackerAnimationData> |
| result_data; |
| result_data.reserve(collected_data.size()); |
| for (const auto& data : collected_data) { |
| api::autotest_private::ThroughputTrackerAnimationData animation_data; |
| animation_data.start_offset_ms = |
| (data.start_tick - g_last_start_throughput_data_collection_tick) |
| .InMilliseconds(); |
| animation_data.stop_offset_ms = |
| (data.stop_tick - g_last_start_throughput_data_collection_tick) |
| .InMilliseconds(); |
| animation_data.frames_expected = data.smoothness_data.frames_expected; |
| animation_data.frames_produced = data.smoothness_data.frames_produced; |
| animation_data.jank_count = data.smoothness_data.jank_count; |
| result_data.emplace_back(std::move(animation_data)); |
| } |
| return RespondNow(ArgumentList( |
| api::autotest_private::GetThroughputTrackerData::Results::Create( |
| result_data))); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateGetDisplaySmoothnessFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateGetDisplaySmoothnessFunction:: |
| AutotestPrivateGetDisplaySmoothnessFunction() = default; |
| |
| AutotestPrivateGetDisplaySmoothnessFunction:: |
| ~AutotestPrivateGetDisplaySmoothnessFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| AutotestPrivateGetDisplaySmoothnessFunction::Run() { |
| auto params( |
| api::autotest_private::GetDisplaySmoothness::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* root_window = ash::Shell::GetRootWindowForDisplayId(display_id); |
| const uint32_t smoothness = |
| 100 - root_window->GetHost()->compositor()->GetPercentDroppedFrames(); |
| return RespondNow( |
| ArgumentList(api::autotest_private::GetDisplaySmoothness::Results::Create( |
| smoothness))); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateResetHoldingSpaceFunction |
| //////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateResetHoldingSpaceFunction:: |
| AutotestPrivateResetHoldingSpaceFunction() = default; |
| |
| AutotestPrivateResetHoldingSpaceFunction:: |
| ~AutotestPrivateResetHoldingSpaceFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| AutotestPrivateResetHoldingSpaceFunction::Run() { |
| auto params(api::autotest_private::ResetHoldingSpace::Params::Create(args())); |
| EXTENSION_FUNCTION_VALIDATE(params); |
| |
| Profile* profile = Profile::FromBrowserContext(browser_context()); |
| |
| ash::HoldingSpaceKeyedService* service = |
| ash::HoldingSpaceKeyedServiceFactory::GetInstance()->GetService(profile); |
| |
| if (service == nullptr) |
| return RespondNow(Error("Failed to get `HoldingSpaceKeyedService`.")); |
| |
| service->RemoveAll(); |
| |
| PrefService* prefs = profile->GetPrefs(); |
| ash::holding_space_prefs::ResetProfilePrefsForTesting(prefs); |
| |
| if (!ash::holding_space_prefs::MarkTimeOfFirstAvailability(prefs)) { |
| return RespondNow( |
| Error("Failed to call `MarkTimeOfFirstAvailability()` after clearing " |
| "prefs.")); |
| } |
| |
| if (!params->options || !params->options->mark_time_of_first_add) |
| return RespondNow(NoArguments()); |
| |
| if (!ash::holding_space_prefs::MarkTimeOfFirstAdd(prefs)) { |
| return RespondNow( |
| Error("Failed to call `MarkTimeOfFirstAdd()` after clearing prefs.")); |
| } |
| |
| return RespondNow(NoArguments()); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateStartLoginEventRecorderDataCollectionFunction |
| ////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateStartLoginEventRecorderDataCollectionFunction:: |
| AutotestPrivateStartLoginEventRecorderDataCollectionFunction() = default; |
| |
| AutotestPrivateStartLoginEventRecorderDataCollectionFunction:: |
| ~AutotestPrivateStartLoginEventRecorderDataCollectionFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| AutotestPrivateStartLoginEventRecorderDataCollectionFunction::Run() { |
| ash::LoginEventRecorder::Get() |
| ->PrepareEventCollectionForTesting(); // IN-TEST |
| return RespondNow(NoArguments()); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateGetLoginEventRecorderLoginEventsFunction |
| ////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateGetLoginEventRecorderLoginEventsFunction:: |
| AutotestPrivateGetLoginEventRecorderLoginEventsFunction() = default; |
| |
| AutotestPrivateGetLoginEventRecorderLoginEventsFunction:: |
| ~AutotestPrivateGetLoginEventRecorderLoginEventsFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| AutotestPrivateGetLoginEventRecorderLoginEventsFunction::Run() { |
| const auto& collected_data = |
| ash::LoginEventRecorder::Get() |
| ->GetCollectedLoginEventsForTesting(); // IN-TEST |
| std::vector<api::autotest_private::LoginEventRecorderData> result_data; |
| for (const auto& data : collected_data) { |
| api::autotest_private::LoginEventRecorderData event_data; |
| event_data.name = data.name(); |
| event_data.microsecnods_since_unix_epoch = |
| (data.time() - base::TimeTicks::UnixEpoch()).InMicroseconds(); |
| result_data.emplace_back(std::move(event_data)); |
| } |
| |
| return RespondNow(ArgumentList( |
| api::autotest_private::GetLoginEventRecorderLoginEvents::Results::Create( |
| result_data))); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateAddLoginEventForTestingFunction |
| ////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateAddLoginEventForTestingFunction:: |
| AutotestPrivateAddLoginEventForTestingFunction() = default; |
| |
| AutotestPrivateAddLoginEventForTestingFunction:: |
| ~AutotestPrivateAddLoginEventForTestingFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| AutotestPrivateAddLoginEventForTestingFunction::Run() { |
| ash::LoginEventRecorder::Get()->AddLoginTimeMarker( |
| /*marker_name=*/"AutotestPrivateTestMarker", |
| /*send_to_uma=*/false, |
| /*write_to_file=*/false); |
| return RespondNow(NoArguments()); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateForceAutoThemeModeFunction |
| ////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateForceAutoThemeModeFunction:: |
| AutotestPrivateForceAutoThemeModeFunction() = default; |
| |
| AutotestPrivateForceAutoThemeModeFunction:: |
| ~AutotestPrivateForceAutoThemeModeFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| AutotestPrivateForceAutoThemeModeFunction::Run() { |
| DVLOG(1) << "AutotestPrivateForceAutoThemeModeFunction"; |
| |
| std::unique_ptr<api::autotest_private::ForceAutoThemeMode::Params> params( |
| api::autotest_private::ForceAutoThemeMode::Params::Create(args())); |
| EXTENSION_FUNCTION_VALIDATE(params); |
| |
| ash::DarkLightModeController* dark_light_mode_controller = |
| ash::DarkLightModeController::Get(); |
| DCHECK(dark_light_mode_controller); |
| |
| dark_light_mode_controller->SetDarkModeEnabledForTest( |
| params->dark_mode_enabled); |
| return RespondNow(NoArguments()); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateGetAccessTokenFunction |
| ////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateGetAccessTokenFunction::AutotestPrivateGetAccessTokenFunction() = |
| default; |
| |
| AutotestPrivateGetAccessTokenFunction:: |
| ~AutotestPrivateGetAccessTokenFunction() = default; |
| |
| ExtensionFunction::ResponseAction AutotestPrivateGetAccessTokenFunction::Run() { |
| // Require a command line switch to avoid crashing on accident. |
| if (!base::CommandLine::ForCurrentProcess()->HasSwitch( |
| ash::switches::kGetAccessTokenForTest)) { |
| return RespondNow( |
| Error("* switch is not set", ash::switches::kGetAccessTokenForTest)); |
| } |
| // This API is available only on test images. |
| base::SysInfo::CrashIfChromeOSNonTestImage(); |
| |
| auto params(api::autotest_private::GetAccessToken::Params::Create(args())); |
| EXTENSION_FUNCTION_VALIDATE(params.get()); |
| |
| timeout_timer_.Start( |
| FROM_HERE, |
| base::Milliseconds(params->access_token_params.timeout_ms |
| ? *params->access_token_params.timeout_ms |
| : 90000), |
| base::BindOnce( |
| &AutotestPrivateGetAccessTokenFunction::RespondWithTimeoutError, |
| this)); |
| |
| Profile* profile = Profile::FromBrowserContext(browser_context()); |
| signin::IdentityManager* identity_manager = |
| IdentityManagerFactory::GetForProfile(profile); |
| OAuth2AccessTokenManager::ScopeSet scopes( |
| params->access_token_params.scopes.begin(), |
| params->access_token_params.scopes.end()); |
| access_token_fetcher_ = identity_manager->CreateAccessTokenFetcherForAccount( |
| identity_manager |
| ->FindExtendedAccountInfoByEmailAddress( |
| params->access_token_params.email) |
| .account_id, |
| /*oauth_consumer_name=*/"cros_autotest_private", scopes, |
| base::BindOnce(&AutotestPrivateGetAccessTokenFunction::OnAccessToken, |
| this), |
| signin::AccessTokenFetcher::Mode::kImmediate); |
| return RespondLater(); |
| } |
| |
| void AutotestPrivateGetAccessTokenFunction::RespondWithTimeoutError() { |
| if (did_respond()) { |
| return; |
| } |
| Respond(Error("Timed out fetching access token")); |
| access_token_fetcher_.reset(); |
| } |
| |
| void AutotestPrivateGetAccessTokenFunction::OnAccessToken( |
| GoogleServiceAuthError error, |
| signin::AccessTokenInfo token_info) { |
| access_token_fetcher_.reset(); |
| timeout_timer_.AbandonAndStop(); |
| if (did_respond()) { |
| return; |
| } |
| if (error.state() != GoogleServiceAuthError::NONE) { |
| Respond(Error("Failed to get access token: *", error.ToString())); |
| return; |
| } |
| base::Value::Dict token_dict; |
| token_dict.Set("accessToken", token_info.token); |
| token_dict.Set( |
| "expirationTimeUnixMs", |
| base::Int64ToValue((token_info.expiration_time - base::Time::UnixEpoch()) |
| .InMilliseconds())); |
| Respond(WithArguments(std::move(token_dict))); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateIsInputMethodReadyForTestingFunction |
| ////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateIsInputMethodReadyForTestingFunction:: |
| AutotestPrivateIsInputMethodReadyForTestingFunction() = default; |
| |
| AutotestPrivateIsInputMethodReadyForTestingFunction:: |
| ~AutotestPrivateIsInputMethodReadyForTestingFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| AutotestPrivateIsInputMethodReadyForTestingFunction::Run() { |
| ash::TextInputMethod* engine = |
| ash::IMEBridge::Get()->GetCurrentEngineHandler(); |
| return RespondNow( |
| WithArguments(engine && engine->IsReadyForTesting())); // IN-TEST |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateMakeFuseboxTempDirFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateMakeFuseboxTempDirFunction:: |
| ~AutotestPrivateMakeFuseboxTempDirFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| AutotestPrivateMakeFuseboxTempDirFunction::Run() { |
| fusebox::Server* server = fusebox::Server::GetInstance(); |
| if (!server) { |
| return RespondNow(Error("Fusebox server instance not available")); |
| } |
| server->MakeTempDir(base::BindOnce( |
| &AutotestPrivateMakeFuseboxTempDirFunction::OnMakeTempDir, this)); |
| return RespondLater(); |
| } |
| |
| void AutotestPrivateMakeFuseboxTempDirFunction::OnMakeTempDir( |
| const std::string& error_message, |
| const std::string& fusebox_file_path, |
| const std::string& underlying_file_path) { |
| if (!error_message.empty()) { |
| Respond(Error(error_message)); |
| return; |
| } |
| base::Value::Dict dict; |
| dict.Set("fuseboxFilePath", fusebox_file_path); |
| dict.Set("underlyingFilePath", underlying_file_path); |
| Respond(WithArguments(std::move(dict))); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateRemoveFuseboxTempDirFunction |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateRemoveFuseboxTempDirFunction:: |
| ~AutotestPrivateRemoveFuseboxTempDirFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| AutotestPrivateRemoveFuseboxTempDirFunction::Run() { |
| std::unique_ptr<api::autotest_private::RemoveFuseboxTempDir::Params> params( |
| api::autotest_private::RemoveFuseboxTempDir::Params::Create(args())); |
| EXTENSION_FUNCTION_VALIDATE(params); |
| |
| fusebox::Server* server = fusebox::Server::GetInstance(); |
| if (!server) { |
| return RespondNow(Error("Fusebox server instance not available")); |
| } |
| server->RemoveTempDir(params->fusebox_file_path); |
| return RespondNow(NoArguments()); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateRemoveComponentExtension |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateRemoveComponentExtensionFunction:: |
| ~AutotestPrivateRemoveComponentExtensionFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| AutotestPrivateRemoveComponentExtensionFunction::Run() { |
| std::unique_ptr<api::autotest_private::RemoveComponentExtension::Params> |
| params(api::autotest_private::RemoveComponentExtension::Params::Create( |
| args())); |
| EXTENSION_FUNCTION_VALIDATE(params); |
| |
| extensions::ExtensionService* extension_service = |
| extensions::ExtensionSystem::Get(browser_context())->extension_service(); |
| extension_service->component_loader()->Remove(params->extension_id); |
| |
| return RespondNow(NoArguments()); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateStartFrameCountingFunction |
| ////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateStartFrameCountingFunction:: |
| AutotestPrivateStartFrameCountingFunction() = default; |
| |
| AutotestPrivateStartFrameCountingFunction:: |
| ~AutotestPrivateStartFrameCountingFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| AutotestPrivateStartFrameCountingFunction::Run() { |
| std::unique_ptr<api::autotest_private::StartFrameCounting::Params> params( |
| api::autotest_private::StartFrameCounting::Params::Create(args())); |
| EXTENSION_FUNCTION_VALIDATE(params); |
| |
| if (params->bucket_size_in_seconds <= 0) { |
| return RespondNow( |
| Error("Param bucketSizeInSeconds must be greater than 0s")); |
| } |
| |
| // "viz.mojom.FrameCountingPerSinkData" uses uint16 to store frame counts. |
| // Limit the max bucket size so that the max frame count does not go beyond |
| // uint16 max. 500s is safe even for a 120fps system. |
| constexpr int kMaxBucketSizeInSeconds = 500; |
| if (params->bucket_size_in_seconds > kMaxBucketSizeInSeconds) { |
| return RespondNow( |
| Error("Param bucketSizeInSeconds must be less than 500s")); |
| } |
| |
| aura::Env::GetInstance() |
| ->context_factory() |
| ->GetHostFrameSinkManager() |
| ->StartFrameCountingForTest( // IN-TEST |
| base::Seconds(params->bucket_size_in_seconds)); |
| return RespondNow(NoArguments()); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // AutotestPrivateStopFrameCountingFunction |
| ////////////////////////////////////////////////////////////////////////////// |
| |
| AutotestPrivateStopFrameCountingFunction:: |
| AutotestPrivateStopFrameCountingFunction() = default; |
| |
| AutotestPrivateStopFrameCountingFunction:: |
| ~AutotestPrivateStopFrameCountingFunction() = default; |
| |
| ExtensionFunction::ResponseAction |
| AutotestPrivateStopFrameCountingFunction::Run() { |
| auto callback = base::BindOnce( |
| &AutotestPrivateStopFrameCountingFunction::OnDataReceived, this); |
| aura::Env::GetInstance() |
| ->context_factory() |
| ->GetHostFrameSinkManager() |
| ->StopFrameCountingForTest(std::move(callback)); // IN-TEST |
| return RespondLater(); |
| } |
| |
| void AutotestPrivateStopFrameCountingFunction::OnDataReceived( |
| viz::mojom::FrameCountingDataPtr data_ptr) { |
| if (!data_ptr || data_ptr->per_sink_data.empty()) { |
| Respond(Error("No frame counting data")); |
| return; |
| } |
| |
| std::vector<api::autotest_private::FrameCountingPerSinkData> result; |
| for (const auto& per_sink_data : data_ptr->per_sink_data) { |
| api::autotest_private::FrameCountingPerSinkData result_per_sink_data; |
| result_per_sink_data.sink_type = |
| CompositorFrameSinkTypeToString(per_sink_data->type); |
| result_per_sink_data.is_root = per_sink_data->is_root; |
| |
| std::copy(per_sink_data->presented_frames.begin(), |
| per_sink_data->presented_frames.end(), |
| std::back_inserter(result_per_sink_data.presented_frames)); |
| |
| result.emplace_back(std::move(result_per_sink_data)); |
| } |
| |
| Respond(ArgumentList( |
| api::autotest_private::StopFrameCounting::Results::Create(result))); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // 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, |
| base::Value::List())); |
| event_router->BroadcastEvent(std::move(event)); |
| } |
| |
| } // namespace extensions |